luogu P2679——子串
?如題,我們分析一下。好像是一個dp???
對啊好像是。
那么想一下狀態;
dp[ i ][ j ][ k ]表示a串匹配到i的位置,b串匹配到j的位置,用了k個子串的方案數;
當a[i]==b[j]時,則有兩種情況:
一是可以自己成為一個子串:dp[i-1][j-1][k-1];
二是和前一個湊成一個子串:dp[i-1][j-1][k];
那么轉移方程就為
dp[ i ][ j ][ k ]=(dp[i-1][j-1][k-1]+dp[i-1][j-1][k])%mod;
可是好像有一些問題,就是這一個位置就算他們相等也可以不選,跳過;
那么我們就要重設狀態了;
dp[ i ][ j ][ k ][0/1]表示當前這個字符選(0)/選不選無所謂( 1 )的方案數;
但是我們看一下數據范圍1000*200*200*2*4(int的字節)/1024/1024=305.17578125>128;
肯定是開不下的,那我們嘗試把第一維抹掉;
dp[ j ][ k ][0]表示b字符串中匹配到j這個位置,用了k個子串,并且當前這個位置一定選的方案數;
dp[ j ][ k ][1]表示b字符串中匹配到j這個位置,用了k個子串,并且當前這個位置不一定選的方案數;
當a[i]==b[j]時,dp[ j ][ k ][0]仍舊有兩種轉移
一是可以自己成為一個子串,不管前面一個選或不選:dp[j-1][k-1][1];
二是和前一個湊成一個子串:dp[j-1][k][0];
那么dp[ j ][ k ][1]的轉移為
一當前這一位取:dp[ j ][ k ][0];
二當前這一位不取:dp[ j ][ k ][1];
如果a[ i ]!=a[ j ]
那么當前b里這一位選的方案數肯定是0:dp[j][k][0]=0;
最后只需要輸出dp[b字符串的長度][子串總數][1]即可,因為最后一位可取可不取;
既然是dp方程,肯定要有初值的啊
dp[0][0][0]=dp[0][0][1]=1;(某神犇傳授的經驗,一般求方案數的dp,邊界條件都是1)
然后就結束了;
感謝葉犇犇的指導;
貼一發 ↑ 神犇的博客
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; const int mod=1000000007; char a[1200],b[210]; int n,m,tot; int dp[210][210][3]; int main() {scanf("%d%d%d",&n,&m,&tot);cin>>a+1;cin>>b+1;/*for(int i=1;i<=n;i++)cout<<a[i]<<" ";cout<<endl;for(int i=1;i<=m;i++)cout<<b[i]<<" ";*/dp[0][0][0]=dp[0][0][1]=1;//第三維是零表示這一位必選,是1表示選不選都行; for(int i=1;i<=n;i++)for(int j=m;j>=1;j--)for(int k=1;k<=tot;k++){if(a[i]==b[j]){dp[j][k][0]=(dp[j-1][k][0]+dp[j-1][k-1][1])%mod;//獨自成一串(dp[j-1][k-1][1])或者是與前面成一串 ( dp[j-1][k][0]); dp[j][k][1]=(dp[j][k][0]+dp[j][k][1])%mod;//當前這一位取的話就是dp[j][k][0],不取的話就是dp[j][k][1](這其實是從上一位轉移過來的); }elsedp[j][k][0]=0; }printf("%d",dp[m][tot][1]);return 0; } 標程轉載注明來源,謝謝;
轉載于:https://www.cnblogs.com/royal-8/p/9084860.html
總結
以上是生活随笔為你收集整理的luogu P2679——子串的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【MVC】Controller的使用
- 下一篇: kafka shell