zoukankan      html  css  js  c++  java
  • CF582E Boolean Function

    良心出题人,表达式给的贼严谨,避免了写烦人的模拟

    首先我们阅读题目之后发现这道题的表达式在每一步后面都套了个括号(甚至是变量都套了),因此我们可以很方便地对于一个表达式找到它中间的运算符,然后把它分成两个子表达式

    于是我们发现所有表达式之间构成了一棵二叉树的关系,因此可以很方便地处理

    接下来考虑算答案,设$f_{x,s}$表示节点$x$表示的子表达式在给定的$n$个$F(A,B,C,D)$下的值状压起来是多少

    叶子节点的答案显然可以直接赋给它,否则我们有转移:

    [ f_{x,ioperatorname{opt} j}+=f_{lson_x,i} imes f_{rson_x,i} ]

    其中$operatorname=&(或)operatorname=|$,显然可以用FWT优化,总复杂度$O(|S| imes n imes 2^n)$

    #include<cstdio>
    #include<cstring>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=505,S=1<<16,mod=1e9+7;
    char s[N]; int len,n,U,f[N][S],tot,x,tar[5];
    inline void inc(int& x,CI y) { if ((x+=y)>=mod) x-=mod; }
    inline void dec(int& x,CI y) { if ((x-=y)<0) x+=mod; }
    namespace Poly
    {
    	inline void FWT_OR(int *f,CI opt)
    	{
    		for (RI i=1,j,k;i<=U;i<<=1) for (j=0;j<=U;j+=(i<<1))
    		for (k=0;k<i;++k) if (~opt) inc(f[i+j+k],f[j+k]); else dec(f[i+j+k],f[j+k]);
    	}
    	inline void FWT_AND(int *f,CI opt)
    	{
    		for (RI i=1,j,k;i<=U;i<<=1) for (j=0;j<=U;j+=(i<<1))
    		for (k=0;k<i;++k) if (~opt) inc(f[j+k],f[i+j+k]); else dec(f[j+k],f[i+j+k]);
    	}
    };
    inline int DP(CI l,CI r)
    {
    	int now=++tot; RI i; if (r-l==2)
    	{
    		if (s[l+1]>='A'&&s[l+1]<='D') ++f[now][tar[s[l+1]-'A']]; else
    		if (s[l+1]>='a'&&s[l+1]<='d') ++f[now][U^tar[s[l+1]-'a']]; else
    		for (i=0;i<4;++i) ++f[now][tar[i]],++f[now][U^tar[i]]; return now;
    	}
    	int pos,cur=0; for (i=l+1;i<=r-1;++i)
    	if (s[i]=='(') ++cur; else if (s[i]==')') --cur;
    	else if (!cur) { pos=i; break; }
    	int ls=DP(l+1,pos-1),rs=DP(pos+1,r-1);
    	if (s[pos]!='&')
    	{
    		Poly::FWT_OR(f[ls],1); Poly::FWT_OR(f[rs],1); Poly::FWT_OR(f[now],1);
    		for (i=0;i<=U;++i) inc(f[now][i],1LL*f[ls][i]*f[rs][i]%mod);
    		Poly::FWT_OR(f[ls],-1); Poly::FWT_OR(f[rs],-1); Poly::FWT_OR(f[now],-1);
    	}
    	if (s[pos]!='|')
    	{
    		Poly::FWT_AND(f[ls],1); Poly::FWT_AND(f[rs],1); Poly::FWT_AND(f[now],1);
    		for (i=0;i<=U;++i) inc(f[now][i],1LL*f[ls][i]*f[rs][i]%mod);
    		Poly::FWT_AND(f[ls],-1); Poly::FWT_AND(f[rs],-1); Poly::FWT_AND(f[now],-1);
    	}
    	return now;
    }
    int main()
    {
    	RI i,j; scanf("%s",s+1); len=strlen(s+1); s[0]='('; s[++len]=')';
    	for (scanf("%d",&n),i=0;i<n;++i) for (j=0;j<5;++j) scanf("%d",&x),tar[j]|=x<<i;
    	return U=(1<<n)-1,printf("%d",f[DP(0,len)][tar[4]]),0;
    }
    
  • 相关阅读:
    Java IO(三)
    Java IO(二)
    Java IO(一)
    Java操作属性文件与国际化
    Java集合详解二
    Java集合详解一
    Spring官方文档翻译(转)
    S2SH整合
    NX二次开发-UFUN获取图纸视图最大边界和视图中心点UF_DRAW_ask_view_borders
    已知两点计算直线的向量
  • 原文地址:https://www.cnblogs.com/cjjsb/p/14074050.html
Copyright © 2011-2022 走看看