Codeforces 582E. Boolean Function 题解

题目链接:E. Boolean Function

题目大意:洛谷


题解:强烈建议在清醒的情况下写这题。因为所有的情况一共只有 \(2^4=16\) 种,所以我们可以对这个状压,即压缩所有选择的方案中每一个方案的结果,在表达式树上 DP ,然后我们发现转移一个 FWT 的形式,所以直接套板子即可。(初值的地方坑了我好久),时间复杂度 \(O(\left| S \right| \cdot 16\cdot 2^{16})\)

代码:

#include <cstdio>
const int Maxn=500;
const int Maxm=(1<<16);
const int Mod=1000000007;
int n,m;
char s[Maxn+5];
int f[Maxn+5][Maxm+5];
int lson[Maxn+5],rson[Maxn+5],id_tot;
int g[9][Maxm+5];
void init(){
	for(int i=0;i<4;i++){
		int t=0;
		for(int j=0;j<16;j++){
			t|=(((j>>i)&1)<<j);
		}
		g[i][t]++;
		g[i+4][(Maxm-1)^t]++;
		g[8][t]++;
		g[8][(Maxm-1)^t]++;
	}
}
void FWT_or(int *a,int flag,int len){
	for(int i=1;i<len;i<<=1){
		for(int j=0;j<len;j+=(i<<1)){
			for(int k=0;k<i;k++){
				if(flag==1){
					a[i+j+k]=(a[i+j+k]+a[j+k])%Mod;
				}
				else{
					a[i+j+k]=(a[i+j+k]-a[j+k]+Mod)%Mod;
				}
			}
		}
	}
}
void FWT_and(int *a,int flag,int len){
	for(int i=1;i<len;i<<=1){
		for(int j=0;j<len;j+=(i<<1)){
			for(int k=0;k<i;k++){
				if(flag==1){
					a[j+k]=(a[i+j+k]+a[j+k])%Mod;
				}
				else{
					a[j+k]=(a[j+k]-a[i+j+k]+Mod)%Mod;
				}
			}
		}
	}
}
void merge_or(int *a,int *b,int len){
	static int c[Maxm+5];
	for(int i=0;i<len;i++){
		c[i]=b[i];
	}
	FWT_or(a,1,len);
	FWT_or(c,1,len);
	for(int i=0;i<len;i++){
		a[i]=1ll*a[i]*c[i]%Mod;
	}
	FWT_or(a,-1,len);
}
void merge_and(int *a,int *b,int len){
	static int c[Maxm+5];
	for(int i=0;i<len;i++){
		c[i]=b[i];
	}
	FWT_and(a,1,len);
	FWT_and(c,1,len);
	for(int i=0;i<len;i++){
		a[i]=1ll*a[i]*c[i]%Mod;
	}
	FWT_and(a,-1,len);
}
void work_dfs(int &u,int left,int right){
	static int d[Maxm+5];
	if(left==right){
		u=++id_tot;
		int pos;
		if(s[left]=='?'){
			pos=8;
		}
		else if(s[left]>='A'&&s[left]<='Z'){
			pos=s[left]-'A';
		}
		else{
			pos=s[left]-'a'+4;
		}
		for(int i=0;i<Maxm;i++){
			f[u][i]=g[pos][i];
		}
		return;
	}
	int num=0,mid=-1;
	for(int i=left;i<=right;i++){
		if(s[i]=='('){
			num++;
		}
		if(s[i]==')'){
			num--;
		}
		if(num==0&&(s[i]!='('&&s[i]!=')')){
			mid=i;
			break;
		}
	}
	if(mid==-1){
		work_dfs(u,left+1,right-1);
		return;
	}
	u=++id_tot;
	work_dfs(lson[u],left,mid-1);
	work_dfs(rson[u],mid+1,right);
	if(s[mid]=='|'){
		for(int i=0;i<Maxm;i++){
			f[u][i]=f[lson[u]][i];
		}
		merge_or(f[u],f[rson[u]],Maxm);
	}
	else if(s[mid]=='&'){
		for(int i=0;i<Maxm;i++){
			f[u][i]=f[lson[u]][i];
		}
		merge_and(f[u],f[rson[u]],Maxm);
	}
	else{
		for(int i=0;i<Maxm;i++){
			f[u][i]=f[lson[u]][i];
		}
		merge_or(f[u],f[rson[u]],Maxm);
		for(int i=0;i<Maxm;i++){
			d[i]=f[u][i];
		}
		for(int i=0;i<Maxm;i++){
			f[u][i]=f[lson[u]][i];
		}
		merge_and(f[u],f[rson[u]],Maxm);
		for(int i=0;i<Maxm;i++){
			f[u][i]=(f[u][i]+d[i])%Mod;
		}
	}
}
int a[Maxm+5],b[Maxm+5];
int main(){
	init();
	scanf("%s",s+1);
	while(s[++n]!='\0');
	n--;
	int root=0;
	work_dfs(root,1,n);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int mask=0;
		for(int j=0;j<4;j++){
			int x;
			scanf("%d",&x);
			mask|=(x<<j);
		}
		a[i]=mask;
		scanf("%d",&b[i]);
	}
	int ans=0;
	for(int mask=0;mask<Maxm;mask++){
		bool flag=1;
		for(int i=1;i<=m;i++){
			if(((mask>>a[i])&1)!=b[i]){
				flag=0;
				break;
			}
		}
		if(flag){
			ans=(ans+f[root][mask])%Mod;
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2020-09-14 10:42  with_hope  阅读(351)  评论(0编辑  收藏  举报