题目传送门
解题思路:
f[i][j][p][0/1]表示B前j个字符由A的前i个字符分成p段,且A[i]选或不选的方案数.
一.当B[j] == A[i]时:
1.选A[i]时分三种情况 :
(1)当前A[i-1]可以不选 f[i-1][j-1][p-1][0]
(2)当前A[i]与A[i-1]在同一段上 f[i-1][j-1][p][1]
(3)当前A[i]与A[i-1]不在同一段上 f[i-1][j-1][p-1][1]
2.不选A[i]时,分两种情况:
(1)A[i-1]选 f[i-1][j][p][1]
(2)A[i-1]不选 f[i-1][j][p][0]
二.当B[j]==A[i]时:
1.选A[i] : f[i][j][p][1]=0;
2.不选A[i]同上
好了,这道题的思路就是这样了,但是还有一点需要注意,如果直接写上面的方程的话,会MLE,然后又发现可以压一维,然后就AC了.
//别忘了初始化.
还有最重要的一点:代码第3行的三个人排名不分先后!!!!
先贴一下思路中的未经优化的代码,便于理解:

1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 string a,b; 7 int n,m,w,f[1001][201][201][2]; 8 9 int main() { 10 scanf("%d%d%d",&n,&m,&w); 11 cin >> a >> b; 12 for(int i = 0;i <= n; i++) 13 f[i][0][0][0] = 1; 14 for(int i = 1;i <= n; i++) 15 for(int j = 1;j <= m; j++) 16 for(int k = 1;k <= w; k++) { 17 if(a[i-1] == b[j-1]) { 18 f[i][j][k][1] = f[i-1][j-1][k-1][0] + f[i-1][j-1][k-1][1] + f[i-1][j-1][k][1]; 19 f[i][j][k][0] = f[i-1][j][k][0] + f[i-1][j][k][1]; 20 } 21 else { 22 f[i][j][k][1] = 0; 23 f[i][j][k][0] = f[i-1][j][k][0] + f[i-1][j][k][1]; 24 } 25 } 26 printf("%d",f[n][m][w][1] + f[n][m][w][0]); 27 return 0; 28 }
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #define yyq_ljx_xhy 1000000007 4 //排名不分先后,都可以吊打本蒟蒻 5 using namespace std; 6 7 string a,b; 8 int n,m,w,f[2][201][201][2],p; 9 10 int main() { 11 scanf("%d%d%d",&n,&m,&w); 12 cin >> a >> b; 13 f[1][0][0][0] = f[0][0][0][0] = 1; 14 for(int i = 1;i <= n; i++,p ^= 1) 15 for(int j = 1;j <= m; j++) 16 for(int k = 1;k <= w; k++) { 17 if(a[i-1] == b[j-1]) { 18 f[p][j][k][1] = (f[p^1][j-1][k-1][0] + (f[p^1][j-1][k-1][1] + f[p^1][j-1][k][1]) % yyq_ljx_xhy) % yyq_ljx_xhy; 19 //这里一定要%两次,否则会WA,这说明一个道理,做不出题来,%一下大佬就做出来了 20 f[p][j][k][0] = (f[p^1][j][k][0] + f[p^1][j][k][1]) % yyq_ljx_xhy; 21 } 22 else { 23 f[p][j][k][1] = 0; 24 f[p][j][k][0] = (f[p^1][j][k][0] + f[p^1][j][k][1]) % yyq_ljx_xhy; 25 } 26 } 27 printf("%d",(f[p^1][m][w][1] + f[p^1][m][w][0]) % yyq_ljx_xhy); 28 return 0; 29 }
//NOIP2015提高 Day2 T2