CF gym102586 E. Count Modulo 2【模2下定和选数的方案数】

题目描述:

给出 KK 个互不相同的数 AiA_i,求一个长为 NN 的序列 {xj},xj[1,K]\{x_j\},x_j\in[1,K],满足j=1NAxj=S\sum_{j=1}^NA_{x_j}=S 的方案数模2的值。

K200,N,S1018,0Ai105K\le200,N,S\le10^{18},0\le A_i\le10^5

题目分析:

设每个 AiA_i 出现了 pip_i 次,那么 pi=N,Aipi=S\sum p_i=N,\sum A_ip_i=S,考虑对应到排列上,那么序列 {p}\{p\} 对方案数的贡献次数是 N!pi!\frac {N!}{\prod p_i!}

那么一个序列 {p}\{p\} 的贡献模2余1,则要求上面的式子不能被2整除,我们知道式子中含2的因子数 =i=0N2ij=1Kpj2i=\sum_{i=0}^\infty\left\lfloor\frac N{2^i}\right\rfloor-\sum_{j=1}^K\left\lfloor \frac {p_j}{2^i}\right\rfloor

pi=N\sum p_i=N,与库默尔定理类似,这意味着在二进制下做加法不能进位。即 pip_iNN 二进制下的子集
那么考虑 NN 每一位 1 分配给哪个 pip_i,即求 i=0[N>>i&1]2iAxi=S\sum_{i=0}^\infty[N>>i\&1]2^iA_{x_i}=S
的序列 {x}[1,K]\{x\}\in[1,K] 的方案数模 2

从低位往高位类数位DP,每次可以确定最低位,设状态 f[i][V]f[i][V] 为已经确定了前 ii 位,当前的和为 2iV2^i*V 的方案数,那么转移就是加入一个 AjA_j。然后根据 SS 在当前位的值确定保留哪些方案,然后整体除以2。和最大为 2MaxA2*MaxA
复杂度 O((K+1)MaxAlogN)O((K+1)*MaxA*\log N),bitset优化至 O(KMaxAwlogN+MaxAlogN)O(K*\frac {MaxA}w\log N+MaxA\log N)

Code:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int T,K,A[205],Mx;
LL N,S;
bitset<200005>f,g;
int main()
{
	for(scanf("%d",&T);T--;){
		scanf("%lld%lld%d",&N,&S,&K),Mx=0;
		for(int i=1;i<=K;i++) scanf("%d",&A[i]),Mx=max(Mx,A[i]);
		f.reset(),f[0]=1;
		for(int i=0;N;N>>=1,S>>=1,i++){
			if(N&1){
				g.reset();
				for(int j=1;j<=K;j++) g^=f<<A[j];
			}
			else g=f;
			f.reset();
			for(int j=S&1;j<=2*Mx;j+=2) f[j>>1]=g[j];
		}
		printf("%d\n",int(f[S]));
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章