#3864. Hero meet devil dp套dp + 状压 + 状态机
傳送門
文章目錄
- 題意:
- 思路:
題意:
給你一個只包含ACGTACGTACGT的串sss,再給你一個mmm,第iii行輸出有多少個長度為mmm且只包含ACGTACGTACGT的串與sss的lcslcslcs為iii。
∣s∣≤15,m≤1000|s|\le15,m\le1000∣s∣≤15,m≤1000
思路:
我們簡單回顧一下兩個串的lcslcslcs怎么求。
設f[i][j]f[i][j]f[i][j]表示一個串到了第iii位,另一個串到了第jjj位的lcslcslcs,轉移就分兩種情況
(1)f[i][j]=max(f[i][j?1],f[i?1][j])(1)f[i][j]=max(f[i][j-1],f[i-1][j])(1)f[i][j]=max(f[i][j?1],f[i?1][j])
(2)(2)(2)如果ai==aja_i==a_jai?==aj?,f[i][j]=max(f[i][j],f[i?1][j?1]+1)f[i][j]=max(f[i][j],f[i-1][j-1]+1)f[i][j]=max(f[i][j],f[i?1][j?1]+1)
讓后看這個題,對于字符串的限制我們套路的采用自動機這種東西來輔助轉移,但是對于這個題并沒有一個現成的自動機來幫助我們轉移,所以需要我們自己造一個。
考慮暴力求解?4m4^{m}4m枚舉mmm的所有可能情況,讓后暴力跑?顯然狀態太多存不下,那么是什么我們重復計算了多次呢?
來觀察一下dpdpdp數組,由于我們已經知道sss串,可以發現我們要從dp[i?1]dp[i-1]dp[i?1]轉移過來的時候,需要枚舉i?1i-1i?1的狀態和當前加入了那個字符,不難發現有很多dp[i?1]dp[i-1]dp[i?1]狀態是重復的,并且可以發現dp[i]dp[i]dp[i]是具有單調性的,dp[i]?dp[i?1]∈[0,1]dp[i]-dp[i-1]\in[0,1]dp[i]?dp[i?1]∈[0,1],所以dpdpdp的差分數組是一個010101串!我們可以將其狀壓成一個二進制,這樣就可以將許多重復和無用的狀態壓縮起來,所以設計狀態f[i][j]f[i][j]f[i][j]代表當前的長度為iii時,sss串的dpdpdp差分數組的狀態為jjj,轉移的話就直接枚舉當前要選哪個字母kkk,讓后轉移到next[k][j]next[k][j]next[k][j] ,其中next[k][j]next[k][j]next[k][j]代表狀態為jjj的時候,下一次選kkk字母轉移到的狀態。
我們需要預處理next[k][j]next[k][j]next[k][j]數組,這就是我們“手寫”的一個轉換模型,預處理他也很簡單,直接枚舉[0,(1<<n)?1][0,(1<<n)-1][0,(1<<n)?1]所有的狀態,其中g1[i]g1[i]g1[i]代表到了第iii個加字符kkk的lcslcslcs,g2[i]g2[i]g2[i]代表當前狀態到第iii個的時候的lcslcslcs,讓后枚舉kkk轉移即可,最后能轉移到的狀態就是g1[i]g1[i]g1[i]的差分數組。
具體的看代碼會比較清楚。
O(4?2nm)O(4*2^nm)O(4?2nm)
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #include<random> #include<cassert> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid ((tr[u].l+tr[u].r)>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=110,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n,m; int a[N]; LL f[2][1<<15],ans[N]; int ne[5][1<<15]; int g1[N],g2[N]; char s[N];int get(char ch) {if(ch=='A') return 1;if(ch=='C') return 2;if(ch=='G') return 3;if(ch=='T') return 4;return -1; }void init() {memset(ne,0,sizeof(ne));for(int i=0;i<1<<n;i++) {for(int j=1;j<=n;j++) g2[j]=g2[j-1]+(i>>(j-1)&1);for(int k=1;k<=4;k++) {for(int j=1;j<=n;j++) {g1[j]=max(g1[j-1],g2[j]);if(a[j]==k) g1[j]=max(g1[j],g2[j-1]+1);}int state=0;for(int i=0;i<n;i++) if(g1[i+1]-g1[i]) state+=1<<i;ne[k][i]=state;}} }void solve() {scanf("%d",&m);memset(f[0],0,sizeof(f[0]));memset(f[1],0,sizeof(f[1]));int now=0;f[now][0]=1; now^=1;for(int i=1;i<=m;i++,now^=1) {memset(f[now],0,sizeof(f[now]));for(int k=1;k<=4;k++) {for(int j=0;j<1<<n;j++) {(f[now][ne[k][j]]+=f[now^1][j])%=mod;}}}now^=1;for(int i=0;i<=n;i++) ans[i]=0;for(int i=0;i<1<<n;i++) (ans[__builtin_popcount(i)]+=f[now][i])%=mod; }int main() { // ios::sync_with_stdio(false); // cin.tie(0);int _; scanf("%d",&_);while(_--) {scanf("%s",s+1); n=strlen(s+1);for(int i=1;i<=n;i++) a[i]=get(s[i]);init();solve();for(int i=0;i<=n;i++) printf("%lld\n",ans[i]);}return 0; } /**/總結
以上是生活随笔為你收集整理的#3864. Hero meet devil dp套dp + 状压 + 状态机的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 2018 ICPC Asia Jakar
- 下一篇: 马齿苋怎么煮水治皮肤
