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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

#3864. Hero meet devil dp套dp + 状压 + 状态机

發布時間:2023/12/4 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 #3864. Hero meet devil dp套dp + 状压 + 状态机 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

文章目錄

  • 題意:
  • 思路:

題意:

給你一個只包含ACGTACGTACGT的串sss,再給你一個mmm,第iii行輸出有多少個長度為mmm且只包含ACGTACGTACGT的串與ssslcslcslcsiii

∣s∣≤15,m≤1000|s|\le15,m\le1000s15,m1000

思路:

我們簡單回顧一下兩個串的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個加字符kkklcslcslcsg2[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 + 状压 + 状态机的全部內容,希望文章能夠幫你解決所遇到的問題。

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