[关闭]
@ysner 2018-10-02T15:16:07.000000Z 字数 1884 阅读 1830

[noip模拟赛]算算数

树形DP DP 子集DP FWT


题面

有一天小胡同学看到了一种表达式。这个表达式有四个变量。这四
个变量都只有两种取值。小写字母表示对应变量取反后的值。

小胡同学正准备对一个表达式求值的时候,他发现邪恶的小王把这个表达式
的一些变量或运算符给抹掉了(所有的括号均没被抹掉),小胡同学想复原这个
表达式,他现在有个已知的运算结果。每个运算结果记为,
表示当取对应值的时候整个表达式的结果为
现在小胡同学想知道,有多少个合法的表达式满足所有的运算结果。

解析

算法

一般来说,求表达式的值都是用栈。
然而这样不能应用于

所以有个东西叫表达式树
它的形态是,最底层是所有的数字,两个数字间的运算符作为它们共同的父亲,同时这个父亲代表它们的运算结果,依次类推。。。

为在第个结点,当前运算结果集合为的方案数。
然后每次递归进左边的括号和右边的括号,最后合并左边和右边的答案即可。
(然而并没那么好写)
复杂度。(然而其实|S|中大多数都是括号,运算符可能只有个)
要特别注意当前处理完后,到达下一次处理的字符要挪几位,有时位,有时位。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=100,mod=1e9+7;
  14. int n,m,st[6],S,p,tot,f[505][1<<17];
  15. char s[550];
  16. il ll gi()
  17. {
  18. re ll x=0,t=1;
  19. re char ch=getchar();
  20. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  21. if(ch=='-') t=-1,ch=getchar();
  22. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  23. return x*t;
  24. }
  25. il void dfs(re int x)
  26. {
  27. re int ls,rs;
  28. if(s[p]!='(')
  29. {
  30. if(s[p]=='?') fp(i,0,3) ++f[x][st[i]],++f[x][st[i]^S];
  31. else if(s[p]>='A'&&s[p]<='D') ++f[x][st[s[p]-'A']];
  32. else ++f[x][st[s[p]-'a']^S];
  33. p+=2;//到运算符
  34. return;
  35. }
  36. ++p;dfs(ls=++tot);
  37. char op=s[p];
  38. if(op!='|'&&op!='&'&&op!='?') return;
  39. p+=2;//到右边括号的内部
  40. dfs(rs=++tot);
  41. fp(i,0,S)
  42. fp(j,0,S)
  43. {
  44. if(op!='|') (f[x][i&j]+=1ll*f[ls][i]*f[rs][j]%mod)%=mod;
  45. if(op!='&') (f[x][i|j]+=1ll*f[ls][i]*f[rs][j]%mod)%=mod;
  46. }
  47. ++p;//到达下一次运算
  48. }
  49. int main()
  50. {
  51. freopen("calculate.in","r",stdin);
  52. freopen("calculate.out","w",stdout);
  53. scanf("%s",s+1);n=strlen(s+1);m=gi();S=(1<<m)-1;
  54. fp(i,1,m)
  55. fp(j,0,4) (st[j]<<=1)|=gi();
  56. dfs(tot=p=1);
  57. printf("%d\n",f[1][st[4]]);
  58. fclose(stdin);
  59. fclose(stdout);
  60. return 0;
  61. }

算法

专门用于处理异或、或、与下标时的卷积运算。
通常复杂度为
这样搞一搞,复杂度就成了。
但是这玩意儿应用范围很小,先鸽着。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注