20200603

  • rk 10/10, 60+0+3=63
  • max: 100+50+35+185

石子游戏

相当于选出最少的数使得异或和等于所有数的异或和。显然一定有解,且解的大小 \(<\log a\)(根据线性基理论)。因此从小到大枚举答案,用 fwt 做异或卷积。只需要判断是否非 \(0\) 所以可以把方案数取模,zsy 甚至写了四模数

注意只需要一个位置的点值,手动 ifwt 可以做到 \(O(n\log a)\)

code
const int N = 1<<19;
int n,s;
LL a[N],f[N];

void fwt(LL a[]) {
	for(int i = 1; i < N; i <<= 1) for(int j = 0; j < N; j += i<<1) Rep(k,0,i) {
		LL x = a[j+k], y = a[j+k+i];
		a[j+k] = Mod(x+y), a[j+k+i] = Mod(x-y+mod);
	}
}
void ifwt(LL a[]) {
	for(int i = 1; i < N; i <<= 1) for(int j = 0; j < N; j += i<<1) Rep(k,0,i) {
		LL x = a[j+k], y = a[j+k+i];
		a[j+k] = (x+y) * iv2 %mod, a[j+k+i] = (x-y+mod) * iv2 %mod;
	}
}

signed main() {
#ifdef FS
	freopen("a.in","r",stdin);// freopen("a.out","w",stdout);
#endif
	io>>n; For(i,1,n, x) io>>x, s ^= x, a[x] = 1;
	if( !s ) io<<n, exit(0);
	fwt(a), f[0] = 1, fwt(f);
	for(int i = 1; ; ++i) {
		Rep(j,0,N) (f[j] *= a[j]) %=mod;
		LL cnt=0; Rep(j,0,N) ckadd(cnt, __builtin_parity(s&j)?mod-f[j]:f[j]);
		if( cnt ) io<<n-i, exit(0);
	}
}

函数

可以 min25 但过不了,考虑 PN 筛。

构造 \(g=id_{k}\),归纳得到 \(h(p^{e})=p^{k}-p^{2k}\)

卡常的话可以在 dfs PN 时先只记录每个自然数幂和的系数,这样只需要算一遍自然数幂和

code
const int N = 3.2e6;
int m,sq,pri;
LL n,p[N],hp[N];

struct {
	LL ivf[25],y[25],pre[25],suf[25];
	void init() {
		ivf[0] = ivf[1] = pre[0] = suf[23] = 1;
		For(i,2,22) ivf[i] = (mod-mod/i)*ivf[mod%i]%mod;
		For(i,2,22) (ivf[i] *= ivf[i-1]) %=mod;
		For(i,1,22) y[i] = Mod(y[i-1]+Pow(i,m));
		For(i,1,22) (y[i] *= (22-i&1?mod-1:1)*ivf[i-1]%mod*ivf[22-i]%mod) %=mod;
	}
	LL operator () (LL x) {
		x %=mod;
		For(i,1,22) pre[i] = pre[i-1] * Mod(x-i+mod) %mod;
		rFor(i,22,1) suf[i] = suf[i+1] * Mod(x-i+mod) %mod;
		LL res=0; For(i,1,22) ckadd(res,y[i] * pre[i-1]%mod*suf[i+1]%mod);
		return res;
	}
} L;

void sieve(int n) {
static bitset<N> vis;
	For(i,2,n) {
		if( !vis[i] ) p[++pri] = i;
		for(int j = 1; j <= pri && i*p[j] <= n; ++j)
			{ vis[i*p[j]] = 1; if( !(i % p[j]) ) break; }
	} p[pri+1] = n+1;
	For(i,1,pri) hp[i] = Mod(Pow(p[i],m) - Pow(p[i],2*m) +mod);
}

LL dfs(int i,LL x,LL h) {
	LL y = n/x, res = h * L(y) %mod;
	for(; p[i]*p[i] <= y; ++i) for(LL pe = p[i]*p[i]; pe <= y; pe *= p[i])
		ckadd(res,dfs(i+1,x*pe,h*hp[i]%mod));
	return res;
}

signed main() {
#ifdef FS
	freopen("a.in","r",stdin);// freopen("a.out","w",stdout);
#endif
	io>>n>>m, sq = sqrt(n), sieve(sq), L.init();
	io<<dfs(1,1,1);
	return 0;
}

缠了 zsy 和 yzf 一晚上才明白,感谢两位大佬,我的计数确实太差了

考虑 \(m=0\)。枚举 \(i\) 表示 \(n\) 个数前 \(i\) 位顶上界(且异或和等于 \(C\) 的前 \(i\) 位)。选出一个数使其在当前为 \(<\) 上界,那么其他数低位可以随便填,用该数来控制异或和。可以 DP:设 \(f[j,0/1,0/1]\) 表示前 \(j\) 个数,该位异或和为 \(0/1\),是否有数 \(<\) 上界
注意特判 \(\oplus limit_{i}=C\)

\(m>0\) 的情况可以考虑容斥,钦定边集 \(E\) 不合法(\((u,v)\in E,col_{u}=col_{v}\)),容斥系数为 \((-1)^{|E|}\)\(E\) 会把图分成若干连通块,类似 ABC236Ex 那样优化,一个连通块的容斥系数之和可以由任意连边的 \(-\) 不连通的得到。设 \(f[s,t]\) 表示已经加入的集合 \(s\) 中的点,奇数大小连通块的最小 \(limit\) 取值点集合为 \(t\) 的方案数,枚举补集转移即可
强制新加入的连通块包含补集的最小值那么复杂度为 \(\sum_{i=0}^{n}3^{i}2^{n-i}=O(3^{n})\)

code
const int N = 15;
int n,m,U,mn[1<<N];
LL c,a[N],f[1<<N];
bitset<1<<N> vis;
gp_hash_table<int,LL> g[1<<N];

LL dp(int s) {
static LL b[N],f[N+1][2][2];
	int m = 0; LL ans = 0;
	Rep(i,0,n) if( s>>i & 1 ) b[m++] = a[i];
	rFor(i,59,0) {
		memset(f,0,sizeof f), f[0][0][0] = 1;
		Rep(j,0,m) {
			LL low = ((b[j]&(1ll<<i)-1) + 1) %mod;
			For(k,0,1) For(l,0,1) if( f[j][k][l] ) {
				if( b[j]>>i & 1 ) {
					if( k ) (f[j+1][k][l] += (1ll<<i) %mod * f[j][k][l]) %=mod;
					else ckadd(f[j+1][1][l],f[j][k][l]);
					(f[j+1][k][!l] += f[j][k][l] * low) %=mod;
				} else (f[j+1][k][l] += f[j][k][l] * low) %=mod;
			}
		}
		ckadd(ans,f[m][1][c>>i&1]);
		bool val=0; Rep(j,0,m) val ^= b[j]>>i&1;
		if( val != (c>>i & 1) ) return ans;
	}
	return Add(ans,1);
}

signed main() {
#ifdef FS
	freopen("a.in","r",stdin);// freopen("a.out","w",stdout);
#endif
	io>>n>>m>>c, U = (1<<n)-1; Rep(i,0,n) io>>a[i];
	For(i,1,m, u,v) {
		io>>u>>v, --u,--v;
		For(s,0,U) if( (s>>u & 1) && (s>>v & 1) ) vis[s] = 1;
	}
	For(s,1,U) {
		LL x = LLONG_MAX;
		Rep(i,0,n) if( (s>>i & 1) && ckmin(x,a[i]) ) mn[s] = i;
	}
	For(s,1,U) {
		f[s] = !vis[s];
		for(int t = s-1&s; t; t = t-1&s)
			if( (t & (s&-s)) && !vis[s^t] ) ckdel(f[s],f[t]);
	}
	g[0][0] = 1;
	For(s,0,U) for(auto &gi : g[s]) {
		int t; LL dp; tie(t,dp) = gi;
		for(int i = U^s, j = i; j; j = j-1&i) if( j>>mn[i] & 1 ) {
			if( __builtin_parity(j) )
				(g[s|j][t|1<<mn[j]] += f[j] * dp) %=mod;
			else
				(g[s|j][t] += (a[mn[j]]+1) %mod * f[j] %mod * dp) %=mod;
		}
	}
	LL ans=0; for(auto &i : g[U]) (ans += i.se * dp(i.fi)) %=mod;
	io<<ans;
	return 0;
}
posted @ 2022-06-14 22:08  401rk8  阅读(48)  评论(0编辑  收藏  举报