P2679 子串
题意:现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B 相等?
注意:子串取出的位置不同也认为是不同的方案。
输入输出样例
输入样例#1:
6 3 1 aabaab aab
输出样例#1:
2
输入样例#2:
6 3 2 aabaab aab
输出样例#2:
7
输入样例#3:
6 3 3 aabaab aab
输出样例#3:
7
说明
正解:DP
设f[i][j][0/1]表示分成i个字串,当前在A的k(循环),B串在j(倒着枚举滚动),1:用当前i,2:总的方案
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> using namespace std; #define int long long const int mod=1000000007LL; inline int read() { int f=1,x=0; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { putchar('-'); x=-x; } if(x>9) put(x/10); putchar(x%10+'0'); } inline void in() { freopen("substring.in","r",stdin); freopen("substring.out","w",stdout); } inline void out() { fclose(stdin); fclose(stdout); } int f[250][250][2]; int n; int m; int k; char a[1050]; char b[250]; inline void DPstart() { for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { for(int p=1;p<=k;p++) { if(a[i]!=b[j]) //用i但i不与b相等,所以不合法,方案=0 f[p][j][1]=0; else { if(p==1&&j==1) //边界 { f[p][j][1]=1; //用当前的匹配一个,所以为1 f[p][j][0]++; //相当于+=f[p][j][1];总方案 f[p][j][0]%=mod; //别忘取模 } else { (f[p][j][1]=f[p-1][j-1][0])%=mod; //当前取,且单分 (f[p][j][0]+=f[p][j][1])%=mod; //累加方案 if(i>=2) { if(a[i-1]==b[j-1]) //上一个也相同 { (f[p][j][0]+=f[p][j-1][1])%=mod; //可以拼接把当前与上一个连起来的情况 (f[p][j][1]+=f[p][j-1][1])%=mod; //上一个和这个都取 } } } } } } } } signed main() { // in(); n=read(); m=read(); k=read(); scanf("%s",a+1); scanf("%s",b+1); DPstart(); put(f[k][m][0]%mod); out(); return 0; }
----olinr