被xgc吊打的第一天,Rose's simulate,子集容斥

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Deep_Kevin/article/details/102731502

正题

      前几天才玩过容斥的我在考场上还是一如既往的蠢。

      首先显然min(t_0,t_1,t_?)<=6

      对于min=t_0的情况,我们预处理子集后缀和,每输入一个串,把?\to 0,然后对于原本的0进行容斥。

      对于min=t_1的情况,我们预处理子集前缀和,每输入一个串,把?\to 1,然后对于原本的1进行容斥。

      至于怎么容斥,可以先做做其他子集容斥的题,容斥系数可以用二项式定理简单证明。

      对于min=t_?的情况,暴力枚举即可。

      O(n2^n+Q2^6)

#include<bits/stdc++.h>
using namespace std;

const int N=20;
int n,q,m,ans;
int f[1<<N],g[1<<N],p[1<<N];
int coef[1<<N];
char s[1<<N];

int main(){
	scanf("%d %d",&n,&q);m=1<<n;
	scanf("%s",s);
	for(int i=0;i<m;i++) g[i]=p[i]=f[i]=s[i]-'0';
	for(int l=2;l<=m;l<<=1)
		for(int i=0;i<m;i+=l)
			for(int x=i,y=i+l/2;y<i+l;x++,y++)
				f[y]+=f[x],g[x]+=g[y];
	coef[0]=1;for(int i=1;i<m;i++) coef[i]=-coef[i&(i-1)];
	while(q--){
		scanf("%s",s);
		int t1=0,t2=0,t3=0,a=0,b=0;
		for(int i=0;i<n;i++)
			if(s[i]=='0') t1++;
			else if(s[i]=='1') t2++;
			else t3++;
		ans=0;
		if(t1<=t2 && t1<=t3){
			for(int i=0;i<n;i++){
				a*=2,b*=2;
				if(s[i]=='0') b++;
				else if(s[i]=='1') a++,b++;
			}
			for(int j=b-a;;j=(j-1)&(b-a)){
				ans+=coef[j]*g[a+j];
				if(j==0) break;
			}
		}
		else if(t2<=t1 && t2<=t3){
			for(int i=0;i<n;i++){
				a*=2,b*=2;
				if(s[i]=='1') b++;
				else if(s[i]=='?') a++,b++;
			}
			for(int j=b-a;;j=(j-1)&(b-a)){
				ans+=coef[j]*f[b-j];
				if(j==0) break;
			}
		}
		else{
			for(int i=0;i<n;i++){
				a*=2,b*=2;
				if(s[i]=='?') b++;
				else if(s[i]=='1') a++,b++;
			}
			for(int j=b-a;;j=(j-1)&(b-a)){
				ans+=p[a+j];
				if(j==0) break;
			}
		}
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/102731502