[cf582E]Boolean Function
由于每一个运算都有括号,因此添加的运算不会改变运算顺序
先将其建出一棵表达式树,也就是维护两个栈,是节点和运算符优先级单调递增的栈(设置左括号优先级最低,右括号弹出直至左括号)
每一次运算,也就是新建一个节点(节点上记录操作符),并将栈顶的两个节点作为其儿子即可
关于?是操作符还是变量的判定,只需要根据上一个字符是左括号还是右括号即可
建出表达式树后,令SS是一个224224的二进制数,表示定义fk,Sfk,S表示以kk为根的子树中,每一种取值的答案为SS在该位置上的值的方案数,合并根据or或and做卷积,复杂度为o(Ln2n)o(Ln2n)(L=|s|L=|s|)

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 505 4 #define S (1<<16) 5 #define mod 1000000007 6 stack<int>st_op,st_num; 7 int V,n,ans,a[N],ls[N],rs[N],vis[105],f1[S],f2[S],f3[S],g[11][S],f[N][S]; 8 char s[N]; 9 int turn_num(int k){ 10 if (('A'<=s[k])&&(s[k]<='D'))return s[k]-'A'; 11 if (('a'<=s[k])&&(s[k]<='d'))return s[k]-'a'+4; 12 if ((s[k]=='?')&&((!k)||(s[k-1]=='(')))return 8; 13 return -1; 14 } 15 void merge(){ 16 a[++V]=st_op.top(); 17 st_op.pop(); 18 rs[V]=st_num.top(); 19 st_num.pop(); 20 ls[V]=st_num.top(); 21 st_num.pop(); 22 st_num.push(V); 23 } 24 void FWT_or(int *a,int p){ 25 for(int i=0;i<(1<<4);i++) 26 for(int j=0;j<S;j++) 27 if (j&(1<<i))a[j]=((a[j]+p*a[j^(1<<i)])%mod+mod)%mod; 28 } 29 void FWT_and(int *a,int p){ 30 for(int i=0;i<(1<<4);i++) 31 for(int j=0;j<S;j++) 32 if (j&(1<<i))a[j^(1<<i)]=((a[j^(1<<i)]+p*a[j])%mod+mod)%mod; 33 } 34 void dfs(int k){ 35 if ((!ls[k])&&(!rs[k]))return; 36 dfs(ls[k]); 37 dfs(rs[k]); 38 if (!a[k]){ 39 FWT_and(f[ls[k]],1); 40 FWT_and(f[rs[k]],1); 41 for(int i=0;i<S;i++)f[k][i]=1LL*f[ls[k]][i]*f[rs[k]][i]%mod; 42 FWT_and(f[k],-1); 43 } 44 if (a[k]==1){ 45 FWT_or(f[ls[k]],1); 46 FWT_or(f[rs[k]],1); 47 for(int i=0;i<S;i++)f[k][i]=1LL*f[ls[k]][i]*f[rs[k]][i]%mod; 48 FWT_or(f[k],-1); 49 } 50 if (a[k]==2){ 51 memcpy(f1,f[ls[k]],sizeof(f1)); 52 memcpy(f2,f[rs[k]],sizeof(f2)); 53 FWT_and(f1,1); 54 FWT_and(f2,1); 55 for(int i=0;i<S;i++)f3[i]=1LL*f1[i]*f2[i]%mod; 56 FWT_and(f3,-1); 57 FWT_or(f[ls[k]],1); 58 FWT_or(f[rs[k]],1); 59 for(int i=0;i<S;i++)f[k][i]=1LL*f[ls[k]][i]*f[rs[k]][i]%mod; 60 FWT_or(f[k],-1); 61 for(int i=0;i<S;i++)f[k][i]=(f[k][i]+f3[i])%mod; 62 } 63 } 64 int main(){ 65 scanf("%s",s); 66 n=strlen(s); 67 for(int i=0;i<n;i++){ 68 int p=turn_num(i); 69 if (p!=-1){ 70 a[++V]=p; 71 st_num.push(V); 72 if ((!st_op.empty())&&(st_op.top()!=-1))merge(); 73 } 74 else{ 75 if (s[i]=='(')st_op.push(-1); 76 if (s[i]=='&')st_op.push(0); 77 if (s[i]=='|')st_op.push(1); 78 if (s[i]=='?')st_op.push(2); 79 if (s[i]==')'){ 80 st_op.pop(); 81 if ((!st_op.empty())&&(st_op.top()!=-1))merge(); 82 } 83 } 84 } 85 while (!st_op.empty())merge(); 86 for(int i=0;i<8;i++){ 87 int sta=0; 88 for(int j=0;j<(1<<4);j++) 89 if (((j&(1<<i%4))>0)^(i>=4))sta+=(1<<j); 90 g[i][sta]=1; 91 g[8][sta]++; 92 } 93 for(int i=1;i<=V;i++) 94 if ((!ls[i])&&(!rs[i]))memcpy(f[i],g[a[i]],sizeof(f[i])); 95 dfs(V); 96 memset(vis,-1,sizeof(vis)); 97 scanf("%d",&n); 98 for(int i=1;i<=n;i++){ 99 int k=0,p; 100 for(int j=0;j<4;j++){ 101 scanf("%d",&p); 102 if (p)k+=(1<<j); 103 } 104 scanf("%d",&vis[k]); 105 } 106 for(int i=0;i<S;i++){ 107 bool flag=0; 108 for(int j=0;j<(1<<4);j++) 109 if ((vis[j]>=0)&&(((i&(1<<j))>0)!=vis[j])){ 110 flag=1; 111 break; 112 } 113 if (!flag)ans=(ans+f[V][i])%mod; 114 } 115 printf("%d",ans); 116 }
分类:
codeforces
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 2025成都.NET开发者Connect圆满结束