Proposition

imgimgimg

提供 \(k\) 个变量 \((k\leq 4)\) 可独立取值为 \(0,1\),两种运算分别等价于 \(\neg a\)\(\neg a \lor b\)

你需要恰好使用 \(n\) 个运算符构造一个公式 \(Q\) ,一共 \(m\) 组询问 \((m\leq 500)\),每次寻味有给定一个恰好含有一个 \(Q\) 的公式 \(P\ (|P|\leq 4000)\) ,求有多少种合法的 \(Q\) 使得无论 \(k\) 个变量取何值,\(P\) 的值总为真。

考虑对于 \(k\) 个变量一共有 \(2^k\) 种可能的取值。假设 \(Q\) 已经构造完毕, \(Q\)\(2^k\) 种变量取值可能中分别对应 \(2^k\)\(0,1\),将这 \(2^k\)\(0,1\) 压成一个 \(2^k\) 位的状态,那么一个 \(Q\) 对应着 \(2^{2^k}\) 种状态之一,那么设 \(F_{i,sta}\) 为用 \(i\) 个符号状态为 \(sta\)\(Q\) 的数量。

\[F_{i,sta}=F_{i-1,\neg sta}+\sum\limits_{j+k=i-1,\neg s_1\lor s_2=sta} F_{j,s_1}\times F_{k,s_2} \]

然后对于一个 \(P\) 暴力枚举 \(k\) 个变量的 \(2^k\) 种取值和 \(Q\) 的取值 \((0,1)\) 代入算一遍判断是否合法,这样就得到了对于 \(2^k\) 种变量的取值 \(Q\) 的限制 \(0\)\(1\) 或 都可以。 那么再枚举 \(F\) 所对应的 \(2^{2^k}\) 种取值,将合法的取值加起来即可。

这样单次询问的复杂度为优秀的 \(O(2^{k+1}|P|+2^{2^k})\) ,此时复杂度瓶颈在于朴素 \(DP\) 预处理的 \(O(n^2\times 2^{2^{k+1}})\)

由于\(sta=\neg s_1\lor s_2\)\(i=j+k\),所以可以直接以 \(sta\) 为下标做 \(FWT\) 或卷积,并用 \(i\) 为下标做个背包,可以做到 \(O(n^2\times 2^k\times 2^{2^k})\)

所以最终复杂度为\(O(n^2\times 2^k\times 2^{2^k}+m\times(2^{k+1}|P|+2^{2^k}))\)

#include<bits/stdc++.h>
#define LL long long
#define M 65560
using namespace std;
int read(){
	int nm=0,fh=1; char cw=getchar();
	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
	return nm*fh;
}
#define mod 1000000007
#define add(a,b) (((a)+(b))>=mod?((a)+(b)-mod):((a)+(b)))
#define mns(a,b) (((a)-(b))<0?((a)-(b)+mod):((a)-(b)))
#define mul(a,b) ((LL)(a)*(LL)(b)%mod)
void upd(int &x,int y){x=add(x,y);}
int n,m,len,F[72][M],G[72][M],maxn,LEN,S[M],top,st[M],tp,b[2]; char ch[4002];
void FWT(int *x,int kd){
	for(int tt=1;tt<len;tt<<=1) for(int st=0;st<len;st+=(tt<<1)) for(int pos=st;pos<st+tt;pos++)
		x[pos+tt]=((kd>0)?add(x[pos+tt],x[pos]):mns(x[pos+tt],x[pos]));
}
int op(int x,int y,int kd){return (kd==-3)?((!x)|y):(!y);}
int calc(int STA,int KD){
	for(int i=1;i<=top;i++){
		if(S[i]<-2) st[tp-1]=op(st[tp-1],st[tp],S[i]),tp--;
		else if(S[i]==10) st[++tp]=KD; else if(S[i]==-2) st[++tp]=-2;
		else st[++tp]=((STA>>S[i])&1);
	} return st[(tp=0)+1];
}
bool IN(int x,int tot){return (x&tot)==x;}
int solve(){
	scanf("%s",ch),LEN=strlen(ch),top=tp=0; int res=0;
	for(int i=0;i<LEN;i++){
		if(ch[i]=='(') st[++tp]=-1;
		if(ch[i]=='x') S[++top]=ch[++i]-'1'; if(ch[i]=='Q'){S[++top]=10;}
		if(ch[i]=='-'){for(i++;tp&&st[tp]<=-3;S[++top]=st[tp--]);st[++tp]=-3;}
		if(ch[i]=='~'){S[++top]=-2; while(tp&&st[tp]<=-4) S[++top]=st[tp--];st[++tp]=-4;}
		if(ch[i]==')'){while(tp&&st[tp]<=-3) S[++top]=st[tp--];tp--;}
	} while(tp) S[++top]=st[tp--]; b[0]=b[1]=0;
	for(int i=0;i<maxn;i++) for(int kd=0;kd<2;kd++) b[kd]|=(calc(i,kd)<<i);
	for(int i=0;i<len;i++) if(IN(i,b[1])&&IN((len-1)^i,b[0])) upd(res,F[n][i]); return res;
}
int main(){
	n=read(),m=read(),len=(1<<(maxn=(1<<m)));
	for(int i=0,sta=0;i<m;i++,sta=0){
		for(int now=0;now<maxn;now++) if((now>>i)&1) sta|=(1<<now); F[0][sta]++;
	}
	for(int i=0;i<len;i++) G[0][i]=F[0][(len-1)^i]; FWT(G[0],1),FWT(F[0],1);
	for(int i=1;i<=n;i++){
		memcpy(F[i],G[i-1],sizeof(F[i]));
		for(int k=0;k<i;k++) for(int pos=0;pos<len;pos++) 
			upd(F[i][pos],mul(G[k][pos],F[i-k-1][pos]));
		FWT(F[i],-1),memcpy(G[i],F[i],sizeof(G[i])),reverse(G[i],G[i]+len);
		if(i<n) FWT(F[i],1),FWT(G[i],1);
	}
	for(int T=read();T;--T) printf("%d\n",solve());	return 0;
}
posted @ 2018-11-29 09:14  OYJason  阅读(498)  评论(0编辑  收藏  举报