标签:
题解:(dp)
f(k,i,j)表示分了k段,用了第一个串中的前i个数字,已经构成了第二个串的前j个的方案数
f(k,i,j)=∑f(k−1,l,j−1) 当s1[i]==s2[j]且s1[i−1]!=s2[j−1]其中0<l<i
∑f(k−1,l,j−1)+f(k,i−1,j−1) 当s1[i]==s2[j]且s1[i−1]==s2[j−1]其中0<l<i
第一个转移是独立开辟出一个部分的可能数,第二个是算上之前就已经分了k个部分后把第k个部分扩大的方案数。还是比较好理解的,当然f数组要滚动第一维,不然会爆内存。
我觉得这一道题的难度,都和当年乌龟棋在当时的难度差不多了。但这道题的70分算法O(nm2k)比较好写,所以拉不卡差距。
相信大家在看了我的状态转移之后能想出O(nmk)的方法。其实我们需要维护的就只是那一个∑用一个tmp数组保存一下就好了(详见代码)
AC代码:
#include<cstdio> #include<iostream> using namespace std; #define N 1005 #define M 205 #define mod 1000000007 char a[N],b[M]; int f[2][N][M],n,m,K; int main(){ scanf("%d%d%d",&n,&m,&K); scanf("%s%s",a+1,b+1); for(int i=0;i<=n;i++) f[0][i][0]=1; int k=0; for(int h=1;h<=K;h++){ k^=1; for(int i=0;i<=n;i++) f[k][i][h-1]=0; for(int j=h;j<=m;j++){ for(int i=j;i<=n;i++){ if(a[i]==b[j]){ f[k][i][j]=(f[k][i-1][j-1]+f[k][i-1][j])%mod; f[k][i][j]=(f[k][i][j]+f[k^1][i-1][j-1])%mod; if(i>=2) f[k][i][j]=(f[k][i][j]-f[k][i-2][j-1]+mod)%mod; } else f[k][i][j]=f[k][i-1][j]; } } } printf("%d\n",f[k][n][m]); return 0; }
标签:
原文地址:http://www.cnblogs.com/shenben/p/5656283.html