[CF] CF900D Unusual Sequences

Description

\(Link\)

Solution

若干位数\(\rm and\)起来\(=0\),可以容斥。即\((\ge0)-(\ge1)+(\ge2)-(\ge3)...\)\(\ge{x}\)表示至少有\(x\)位为\(1\)的方案,即至少有\(x\)个不合法)

\(ss[x](superset)\)表示二进制下\(x\)的超集中元素个数(超集中的\(y\)满足\(x\&y=x\),即如果\(x\)的某一位是\(1\),那么\(y\)的这一位也一定是\(1\)\(y\)可以\(=x\)

那么\(ss[j]+=ss[j+(1<<i)]((j\&(1<<i)=0))\)

\(x\)的超集有\(ss[x]\)个数,那么在里面任意选\(2^{ss[x]}-1\)个,它们的\(\&\)至少有\(popcount(x)\)\(1\)

容斥即可。

Code

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7;

int n, x, res, ss[1100005], f[25];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

int qpow(int base, int pw)
{
	int s = 1;
	while (pw)
	{
		if (pw & 1) s = 1ll * s * base % mod;
		base = 1ll * base * base % mod;
		pw >>= 1;
	}
	return s;
}

int t1(int x)
{
	int s = 0;
	while (x)
	{
		s += (x & 1);
		x >>= 1;
	}
	return s;
}

int main()
{
	n = read();
	for (int i = 1; i <= n; i ++ ) x = read(), ss[x] ++ ;
	for (int i = 0; i <= 20; i ++ )
		for (int j = 0; j <= (1 << 20) - 1; j ++ )
			if ((j & (1 << i)) == 0 && (j + (1 << i) <= (1 << 20) - 1))
				ss[j] = (ss[j] + ss[j + (1 << i)]) % mod;
	for (int i = 0; i <= (1 << 20) - 1; i ++ ) f[t1(i)] = (f[t1(i)] + qpow(2, ss[i]) - 1) % mod;
	for (int i = 0, o = 1; i <= 20; i ++ , o = -o) res = (res + 1ll * f[i] * o % mod + mod) % mod;
	printf("%d\n", res);
	return 0;
}
posted @ 2021-03-26 16:25  andysj  阅读(52)  评论(0编辑  收藏  举报