CF582E Boolean Function

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

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

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

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

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

\[f_{x,i\operatorname{opt} j}+=f_{lson_x,i}\times f_{rson_x,i} \]

其中\(\operatorname{opt}=\&\)\(\operatorname{opt}=|\),显然可以用FWT优化,总复杂度\(O(|S|\times n\times 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;
}
posted @ 2020-12-02 15:27  空気力学の詩  阅读(131)  评论(0编辑  收藏  举报