日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【CF582E】Boolean Function 树形DP+FWT

發布時間:2025/4/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【CF582E】Boolean Function 树形DP+FWT 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【CF582E】Boolean Function

題意:給你一個長度為n的表達式,其中未知數有A,B,C,D和?,運算有&和|和?(表達式中用括號確定了唯一的運算順序)。?代表A,B,C,D或&,|。A,B,C,D的值是0或1。再給你m個條件$a,b,c,d,e$,代表A,B,C,D分別等于a,b,c,d時表達式的值為e。求有多少種將?填滿的方式,符合給出的所有條件?

$n\le 500,m\le 2^4$

題解:CF總考這種用二進制表示特殊狀態的題,感覺十分考驗人類的抽象能力。

因為變量的可能情況的只有$2^4$種,所以我們用一個4位的二進制字符表示。這樣一來我們就可以發現可能的表達式只有$2^{2^4}$種,所以我們再用一個16位的二進制來表示一個表達式(不要暈)。這個二進制數的第i位為0/1的意義是:如果把i用二進制表示,則i的每一位代表每個變量的取值。在這些變量分別取這些值時,這個表達式的值為0/1(千萬不要暈)。

因為表達式是一堆括號圍出來的,我們可以將括號的嵌套看成一個樹形結構,并且是一棵二叉樹。我們設f[x][S]表示對于當前節點對應的子樹,有多少種方法使得得到的表達式為S。轉移時我們通過左右兒子的f以及當前節點的運算符即能確定當前節點的f值。然后你會發現轉移的實質就是FWT。。。

#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const int P=1000000007; char str[510]; int n,m,tot; int f[170][(1<<16)+4],g[(1<<16)+4],p1[20],p2[20]; inline void add(int &x,int y) {x+=y; if(x>=P) x-=P;} inline void dec(int &x,int y) {x-=y; if(x<=0) x+=P;} inline void fwt1(int *a) {for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if((i>>h)&1) add(a[i],a[i^(1<<h)]); } inline void ufwt1(int *a) {for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if((i>>h)&1) dec(a[i],a[i^(1<<h)]); } inline void fwt0(int *a) {for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if(!((i>>h)&1)) add(a[i],a[i|(1<<h)]); } inline void ufwt0(int *a) {for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if(!((i>>h)&1)) dec(a[i],a[i|(1<<h)]); } int build(int l,int r) {int x=++tot;if(l==r){int i,j,S;for(j=0;j<4;j++){if(str[l]=='?'||str[l]=='A'+j){for(S=i=0;i<16;i++) if((i>>j)&1) S|=1<<i;f[x][S]++;}if(str[l]=='?'||str[l]=='a'+j){for(S=i=0;i<16;i++) if(!((i>>j)&1)) S|=1<<i;f[x][S]++;}}return x;}int i,mid,t=0;for(i=l;i<=r;i++){t+=(str[i]=='(')-(str[i]==')');if(!t) break;}mid=i+1;int ls=build(l+1,mid-2),rs=build(mid+2,r-1);if(str[mid]=='|'){fwt1(f[ls]),fwt1(f[rs]);for(i=0;i<(1<<16);i++) f[x][i]=1ll*f[ls][i]*f[rs][i]%P;ufwt1(f[x]);}else if(str[mid]=='&'){fwt0(f[ls]),fwt0(f[rs]);for(i=0;i<(1<<16);i++) f[x][i]=1ll*f[ls][i]*f[rs][i]%P;ufwt0(f[x]);}else{fwt0(f[ls]),fwt0(f[rs]);for(i=0;i<(1<<16);i++) g[i]=1ll*f[ls][i]*f[rs][i]%P;ufwt0(g),ufwt0(f[ls]),ufwt0(f[rs]);memcpy(f[x],g,sizeof(g));fwt1(f[ls]),fwt1(f[rs]);for(i=0;i<(1<<16);i++) g[i]=1ll*f[ls][i]*f[rs][i]%P;ufwt1(g);for(i=0;i<(1<<16);i++) add(f[x][i],g[i]);}return x; } int main() {scanf("%s%d",str+1,&m),n=strlen(str+1);int i,j,ans=0,S=0,t;for(i=1;i<=m;i++){for(S=j=0;j<4;j++) scanf("%d",&t),S|=t<<j;scanf("%d",&t),p1[i]=S,p2[i]=t;}build(1,n);for(i=0;i<(1<<16);i++){for(j=1;j<=m;j++) if(((i>>p1[j])&1)!=p2[j]) break;if(j>m) add(ans,f[1][i]);}printf("%d",ans);return 0; }

轉載于:https://www.cnblogs.com/CQzhangyu/p/8682186.html

總結

以上是生活随笔為你收集整理的【CF582E】Boolean Function 树形DP+FWT的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。