1. 程式人生 > >[Luogu 2678] noip15 子串

[Luogu 2678] noip15 子串

color size onclick show 是否 sam radius 爆炸 region

[Luogu 2678] noip15 子串

題目描述

有兩個僅包含小寫英文字母的字符串 A 和 B。現在要從字符串 A 中取出 k 個互不重疊的非空子串,然後把這 k 個子串按照其在字符串 A 中出現的順序依次連接起來得到一 個新的字符串,請問有多少種方案可以使得這個新串與字符串 B 相等?註意:子串取出 的位置不同也認為是不同的方案。

輸入輸出格式

輸入格式:

輸入文件名為 substring.in。

第一行是三個正整數 n,m,k,分別表示字符串 A 的長度,字符串 B 的長度,以及問

題描述中所提到的 k,每兩個整數之間用一個空格隔開。 第二行包含一個長度為 n 的字符串,表示字符串 A。 第三行包含一個長度為 m 的字符串,表示字符串 B。

輸出格式:

輸出文件名為 substring.out。 輸出共一行,包含一個整數,表示所求方案數。由於答案可能很大,所以這裏要求[b]輸出答案對 1,000,000,007 取模的結果。

輸入輸出樣例

輸入樣例#1:
6 3 1 
aabaab 
aab
輸出樣例#1:
2
輸入樣例#2:
6 3 2 
aabaab 
aab
輸出樣例#2:
7
輸入樣例#3:
6 3 3 
aabaab 
aab
輸出樣例#3:
7

說明

技術分享

對於第 1 組數據:1≤n≤500,1≤m≤50,k=1;

對於第 2 組至第 3 組數據:1≤n≤500,1≤m≤50,k=2; 對於第 4 組至第 5 組數據:1≤n≤500,1≤m≤50,k=m; 對於第 1 組至第 7 組數據:1≤n≤500,1≤m≤50,1≤k≤m; 對於第 1 組至第 9 組數據:1≤n≤1000,1≤m≤100,1≤k≤m; 對於所有 10 組數據:1≤n≤1000,1≤m≤200,1≤k≤m。

Solution:

想必在考場上還是需要多多思考,不然一道並不難的DP都不一定做的出

這道其實方程的想到其實並不難,

f[i][j][k][0..1]表示s到第i位,t到第j位,使用了k個子串,第i位是否取

那麽這個算算好像空間有些爆炸,那麽再想想滾動

因為在轉移時候當前狀態只跟i-1的狀態有關,因此就可以對i進行滾動

***雖然我並不是這麽打的,但是我覺得這個狀態更簡單想到

技術分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 const int p=1e9+7; 
 8 int n,m,K,ans=0;
 9 int f[205][205],g[205][205];
10 char s[1005],t[205];
11 int main(){
12     scanf("%d%d%d",&n,&m,&K);
13     scanf("%s%s",s+1,t+1);
14     f[0][0]=g[0][0]=1;
15     for (int i=1;i<=n;++i)
16         for (int j=m;j>=1;--j)
17             for (int k=1;k<=K;++k){
18                 if (s[i]!=t[j]) {f[j][k]=0; continue;}
19                 f[j][k]=(f[j-1][k]+g[j-1][k-1])%p;
20                 (g[j][k]+=f[j][k])%=p;
21             }
22     printf("%d",g[m][K]);
23     return 0;
24 }
View Code

[Luogu 2678] noip15 子串