1. 程式人生 > >【NOIP2015提高組Day2】子串

【NOIP2015提高組Day2】子串

這裡寫圖片描述
這裡寫圖片描述
輸入1:
6 3 1
aabaab
aab
輸入2:
6 3 2
aabaab
aab
輸入3:
6 3 3
aabaab
aab
這裡寫圖片描述
輸出1:
2
輸出2:
7
輸出3:
7
這裡寫圖片描述

小結

我寫這篇部落格是為了記住這樣的套路:字串匹配可用DP。(這是NOIP的題,考場我沒有經驗沒有想到DP,但是有人很屌的A了)
我們設F[i][j][k][0/1]表示A串已經匹配到第i個,B串已經匹配到第j個,已經匹配了k段,0:A[i]不與B[j]匹配,1:反之。
我們可以推出方程:

F[i][j][k][0]=F[i1][j][k][0]+F[i1][j][
k][1];


這個很好理解:
然後看匹配的,有三種情況:
首先必須滿足的條件是A[i]==B[i];
當前第i位與第j位匹配,上一位的情況有:
  1. 與B的第j位匹配,但是不分段;F[i1][j1][k][1]
  2. 與B的第j位匹配,分段;F[i1][j1][k1][1]
  3. 不與B的第j位匹配;F[i1][j1][k][0]
    則轉移結束。
    當然,初始化:首先F[0][0][0][0]=1;,毋庸置疑的,但是由於每個點都可以成為第一個與B匹配的點,所以F[i][0][0][0]=1;
    打一個滾動就可以了。
#include<cstdio>
#include<iostream> #include<cstring> using namespace std; int n,m,K,ans; string A,B; long long f[2][201][201][2]; int main() { freopen("substring.in","r",stdin); freopen("substring.out","w",stdout); scanf("%d%d%d",&n,&m,&K); cin>>A; cin>>B;int i,j,k,now=0
,last=1; f[0][0][0][0]=1; for (i=1;i<=n;++i) { swap(now,last); f[now][0][0][0]=1; for (j=1;j<=m;++j) for (k=1;k<=K;++k) { f[now][j][k][0]=(f[last][j][k][0]+f[last][j][k][1])%1000000007; if(A[i-1]==B[j-1]) f[now][j][k][1]=((f[last][j-1][k][1]+f[last][j-1][k-1][1])%1000000007+f[last][j-1][k-1][0])%1000000007; else f[now][j][k][1]=0; } } printf("%lld\n",(f[now][m][K][0]+f[now][m][K][1])%1000000007); }