zoukankan      html  css  js  c++  java
  • Proposition

    imgimgimg

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

    你需要恰好使用 (n) 个运算符构造一个公式 (Q) ,一共 (m) 组询问 ((mleq 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, eg sta}+sumlimits_{j+k=i-1, eg s_1lor s_2=sta} F_{j,s_1} imes 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 imes 2^{2^{k+1}}))

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

    所以最终复杂度为(O(n^2 imes 2^k imes 2^{2^k}+m imes(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
    ",solve());	return 0;
    }
    
  • 相关阅读:
    计算 sql查询语句所花时间
    iframe自适应高度,以及一个页面加载多个iframe
    窗体移动API和窗体阴影API
    js复习:
    web组合查询:
    web登陆,增删改加分页。
    cookie和Session传值
    控件及其数据传输
    ASP.NET WebForm
    三月总结
  • 原文地址:https://www.cnblogs.com/OYJason/p/10036291.html
Copyright © 2011-2022 走看看