NKOI 3559 子串

来源:互联网 发布:java多线程日志输出 编辑:程序博客网 时间:2024/06/05 21:49

【NOIP2015 Day2】子串

Time Limit:10000MS  Memory Limit:131072K
Total Submit:2 Accepted:2 
Case Time Limit:1000MS

Description

        有两个仅包含小写英文字母的字符串A和B。现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串余字符串B相等?注意:子串取出的位置不同也认为是不同的方案。 

Input

        /*输入文件名为substring.in。*/ 
        第一行是三个正整数n,m,k,分别表示字符串A的长度,字符串B的长度,以及问题描述中所提到的k,每两个整数之间用一个空格隔开。 
        第二行包含一个长度为n的字符串,表示字符串A。 
        第三行包含一个长度为m的字符串,表示字符串B。 

Output

        /*输出文件名为substring.out。*/ 
        输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案1,000,000,007取模的结果。 

Sample Input

样例输入1:6 3 1aabaabaab样例输入2:6 3 2aabaabaab样例输入3:6 3 3aabaabaab

Sample Output

样例输出1:2样例输出2:7样例输出3:7

Hint

输入输出样例说明: 
所有合法方案如下:(加下划线的部分表示取出的子串) 
样例1:aab aab / aab aab 
样例2:a ab aab / a aba ab / a a ba ab / aab a ab / aa b aab / aa baa b / aab aa b 
样例3:a a b aab / a a baa b / a ab a a b / a aba a b / a a b a a b / a a ba a b / aab a a b 

数据规模与约定: 
        对于第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。 

Source

感谢nodgd手打题目


首先我们看的出来这是一道动归

状态:f[k][i][j]表示用A串中的前i个字母构成了k段,已经构成了B串的前j个字符的方案总数。
f[k][i][j]=
                   ∑ f[k-1][p][j-1]                              条件:A[i]==B[j]且A[i-1]!=B[j-1]     0<p<i 
                   ∑ f[k-1][p][j-1]+f[k][i-1][j-1]     条件:A[i]==B[j]且A[i-1]==B[j-1]     0<p<i 
第一个是A[i]独立开辟出一个段的方案数
第二个是把A[i]加入之前的第k段。算上之前就已经分了k个部分后,把第k个部分扩大的方案数
时间复杂度:O(nm2k)   显然会超时
观察发现,每次都要计算前缀状态和∑ dp[k-1][p][j-1]
我们可以用一个Sum[ ][ ][ ]数组来记录下来,避免重复计算,
Sum[k][i][j] = dp[k][i][j] + Sum[k][i-1][j];
时间复杂度可降至  O(nmk) 
我们观察发现dp[k][...][...]只跟dp[k-1][...][...]有关,滚动数组处理即可!
#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int mod=1000000007;int K,n,m;char a[1005],b[205];int f[2][1005][205],sum[2][1005][205];int main(){scanf("%d%d%d",&n,&m,&K);scanf("%s%s",a+1,b+1);int i,j,k;f[0][0][0]=1;for(i=0;i<=n;i++)    sum[0][i][0]=1;/////////初始化for(k=1;k<=K;k++){memset(sum[k&1],0,sizeof(sum[k&1]));memset(f[k&1],0,sizeof(f[k&1]));for(i=1;i<=n;i++)    for(j=1;j<=m;j++){    if(a[i]==b[j]){    f[k&1][i][j]=sum[(k-1)&1][i-1][j-1];    if(a[i-1]==b[j-1])        f[k&1][i][j]=(f[k&1][i][j]+f[k&1][i-1][j-1])%mod;}sum[k&1][i][j]=(sum[k&1][i][j]+f[k&1][i][j]+sum[k&1][i-1][j])%mod;}}int ans=0;for(i=1;i<=n;i++)    ans=(ans+f[K&1][i][m])%mod;cout<<ans;}




0 0
原创粉丝点击