首页 > 其他分享 >AtCoder Beginner Contest 220 H Security Camera

AtCoder Beginner Contest 220 H Security Camera

时间:2023-06-18 20:12:16浏览次数:45  
标签:AtCoder typedef limits Beginner Contest bmod 奇偶性 times sum

洛谷传送门

AtCoder 传送门

看到数据范围猜复杂度是 \(O(\text{poly}(n) 2^{\frac{n}{2}})\),所以考虑折半。

至少有一个端点被选不好算,考虑转成两个端点都被选,但是边数奇偶性与 \(m\) 相同。

称编号 \(< \frac{n}{2}\) 的点为左点,编号 \(\ge \frac{n}{2}\) 的点为右点(点编号从 \(0\) 开始)

设 \(f_S\) 为只考虑左点,点集 \(S\) 的导出子图边数奇偶性,\(g_S\) 为只考虑右点,点集 \(S\) 的导出子图边数奇偶性,\(a_S\) 为右点中与左点点集 \(S\) 连边数量是奇数的点集,题目即求:

\[\sum\limits_{S, T} [f_S \oplus g_T \oplus (|a_S \cap T| \bmod 2) = m \bmod 2] \]

其中 \(|a_S \cup T| \bmod 2\) 是在求 \(S, T\) 之间边数的奇偶性。

考虑枚举 \(f_S = x, g_T = y\),设 \(z = (m \bmod 2) \oplus x \oplus y\) 即 \(|a_S \cap T|\) 的奇偶性。那么就是要算:

\[\sum\limits_{S, T} ([f_S = x] \times [g_T = y] \times [|a_S \cap T| \bmod 2 = z] \]

考虑计算 \(h_P = \sum\limits_{S, T} [a_S \cap T = P] \times [f_S = x] \times [g_T = y]\)。设 \(b_P = \sum\limits_{S} [a_S = P] \times [f_S = x], c_P = [g_P = y]\),那么:

\[h_P = \sum\limits_{S \cap T = P} b_S \times c_T \]

这样就化成了一个比较标准的按位与卷积形式,FWT 即可。

时间复杂度 \(O((n + m) 2^{\frac{n}{2}})\),常数比较大。

code
// Problem: H - Security Camera
// Contest: AtCoder - AtCoder Beginner Contest 220
// URL: https://atcoder.jp/contests/abc220/tasks/abc220_h
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 45;
const int maxm = (1 << 20) + 100;

int n, m, all, f[maxm], g[maxm], a[maxm], to[maxn];
ll ff[maxm], gg[maxm];
vector<int> vc[maxm];
pii e1[maxm], e2[maxm];

inline void FWT(ll *f, int x) {
	for (int k = 1; k < all; k <<= 1) {
		for (int i = 0; i < all; i += (k << 1)) {
			for (int j = 0; j < k; ++j) {
				f[i + j] += f[i + j + k] * x;
			}
		}
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	int m1 = 0, m2 = 0;
	for (int _ = 0, u, v; _ < m; ++_) {
		scanf("%d%d", &u, &v);
		--u;
		--v;
		if (u > v) {
			swap(u, v);
		}
		if (u < n / 2 && v >= n / 2) {
			to[v] |= (1 << u);
		} else if (u < n / 2 && v < n / 2) {
			e1[++m1] = make_pair(u, v);
		} else {
			e2[++m2] = make_pair(u, v);
		}
	}
	for (int S = 0; S < (1 << (n / 2)); ++S) {
		for (int i = 1; i <= m1; ++i) {
			int u = e1[i].fst, v = e1[i].scd;
			if ((S & (1 << u)) && (S & (1 << v))) {
				f[S] ^= 1;
			}
		}
	}
	for (int S = 0; S < (1 << (n - n / 2)); ++S) {
		for (int i = 1; i <= m2; ++i) {
			int u = e2[i].fst, v = e2[i].scd;
			if ((S & (1 << (u - n / 2))) && (S & (1 << (v - n / 2)))) {
				g[S] ^= 1;
			}
		}
	}
	for (int S = 0; S < (1 << (n / 2)); ++S) {
		for (int i = n / 2; i < n; ++i) {
			if (__builtin_parity(to[i] & S)) {
				a[S] |= (1 << (i - n / 2));
			}
		}
		vc[a[S]].pb(S);
	}
	all = (1 << (n - n / 2));
	ll ans = 0;
	for (int x = 0; x <= 1; ++x) {
		for (int y = 0; y <= 1; ++y) {
			for (int S = 0; S < all; ++S) {
				ff[S] = 0;
				for (int T : vc[S]) {
					ff[S] += (f[T] == x);
				}
				gg[S] = (g[S] == y);
			}
			FWT(ff, 1);
			FWT(gg, 1);
			for (int i = 0; i < all; ++i) {
				ff[i] *= gg[i];
			}
			FWT(ff, -1);
			for (int i = 0; i < all; ++i) {
				if ((__builtin_parity(i) ^ x ^ y) == (m & 1)) {
					ans += ff[i];
				}
			}
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,typedef,limits,Beginner,Contest,bmod,奇偶性,times,sum
From: https://www.cnblogs.com/zltzlt-blog/p/17489666.html

相关文章

  • AtCoder Beginner Contest 306 题解 A - E
    A-Echo题目大意给定一个字符串,需要把它每个字符重复输出。解题思路可以读完整个字符串,也可以按照字符读一个输出两个。ACCode#include<iostream>#include<algorithm>#include<cstring>#include<numeric>#defineendl'\n'#defineiosios::sync_with_stdio(fals......
  • AtCoder ABC306 DEF
    D-PoisonousFull-Course(DP)题意现在有\(N\)道菜,高桥需要依次享用。第\(i\)道菜有两个属性\((X_i,Y_i)\),其意义是:若\(X_i=0\),则第\(i\)道菜是解毒的,其美味度为\(Y_i\);若\(X_i=1\),则第\(i\)道菜是有毒的,其美味度为\(Y_i\)。当高桥享用一道菜,他的状态变化如下:......
  • AtCoder Beginner Contest 306 G Return to 1
    洛谷传送门AtCoder传送门考虑若干个能被\(1\)到达且能到达\(1\)的环,设它们的环长分别为\(a_1,a_2,...,a_k\)。那么我们现在要每个环走若干遍,使得步数不含除\(2\)或\(5\)以外的质因子。设第\(i\)个环走\(x_i\)遍,那么其实就是要求\(\sum\limits_{i=1}^ka_i......
  • 【题解】Atcoder ABC300 F.More Holidays(线性做法)
    F.MoreHolidays题目描述:给你一个由o和x组成的长度为\(N\)的字符串\(S\),以及整数\(M\)和\(K\)。保证\(S\)至少包含一个x。假设\(T\)是由\(S\)复制\(M\)次而成的长度为\(NM\)的字符串。考虑将\(T\)中的\(K\)个x恰好替换为o。你的目标是在替换后的......
  • AtCoder Beginner Contest 306
    A-Echo(abc306a)题目大意给定一个字符串,将每个字符输出两次。解题思路模拟即可。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;intmain(void){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);intn;......
  • AtCoder ABC056D 题解
    题目直达0x00思路从大到小枚举每个元素,同时加入\(sum\)进行累计,当\(k\lesum\)时,便会返现之前的元素可以构成“好的组”(因为他们都大于\(p_i\)),即有用的,所以要清空。0x01举个例子36143我们对输入排序后,会得到\(p\)为。431这时,我们的\(i=1\),即\(p_i=......
  • AtCoder ABC228D 题解
    [ABC299D]FindbyQuery题解0x00题目分析题目传送门经过分析,我们得到的几个关键信息:\(n\le2\times10^5\)最多可以问法官\(20\)个问题。s[1]=0,s[n]=1分析\(n\)的范围,发现\(\log_n=17.6096\),刚好比\(20\)小一点点。这时便考虑二分的做法。看到s[1]=0,......
  • AtCoder ABC047D 题解
    题意理解&分析:大概的题意应该是十分清晰的,就是一个人要从\(1\)到\(n\)的城市中买苹果。另一个人要其中调整价格。这里的调整也不需要太多,就\(1\)就可以了。但是,如果有多组购买方案可以得到相同的利润,就还需要将其他相同的价格一并调整。这道题的关键就在于求出有几组购买......
  • AtCoder Beginner Contest 221 G Jumping sequence
    洛谷传送门AtCoder传送门这个数据范围让我们不得不往背包想。但是两维相互限制。考虑坐标系旋转\(45°\),转化为两维不相互限制。那我们现在相当于要安排正负号,使得\(\sum\limits_{i=1}^n\pmd_i\)等于一个给定的值\(K\)。考虑两边加上\(\sum\limits_{i=1}^nd_i\)......
  • AtCoder Beginner Contest 294 E
    AtCoderBeginnerContest294E-2xNGridProblemStatement题意:给你\(2\)行长度为\(L\)的矩阵。告诉你格子里面的数字,以\(vi\)\(li\)的形式:\(vi\)有\(li\)个问上下两个一样的有多少个?解释:以样例为例输入84312322331142133输出4第$1,$2,\(5\),8个上......