uoj#149
dp
没想出来 最先开始想 dp[i][j][k]表示s匹配到i,t匹配到j,当前分了k段的方案数
s[i]==t[j] dp[i][j][k]+=dp[i-1][j-1][k-1] s[i]==t[j]&&s[i-1]==t[j-1] dp[i][j][k]+=dp[i-1][j-1][k] dp[i][j][k]+=dp[i-1][j][k]
问题出在中间那个式子,但是我不知道怎么改,这样会多出来很多状态,比如说aabaab和aabk=1
dp[5][2][1]=4 因为dp[5][2][1]+=dp[4][1][1] 但是这样会出现不连续的,第一个a和第5个a匹配了,因为上一个方案可能没选那位,但是我们当成可以接在上一个后面。
那么我们再定义一个f[i][j][k]表示s匹配到i,t匹配到j,分成k段,i和j同时选的方案数。这样就解决了刚才的那个问题,dp[i][j][k]=dp[i-1][j][k]+f[i][j][k]
s[i]==t[j] f[i][j][k]=f[i-1][j-1][k]+dp[i-1][j-1][k-1] 否则f[i][j][k]=0
这样就可以转移了
如果当前dp不满足一些转移的条件,我们可以创造一些条件,比如多设一个数组,在树形dp求直径也用到了这样的思路。
#include<bits/stdc++.h> using namespace std; const int N = 1010, mod = 1000000007; int n, m, k, pre; int dp[2][N][N], f[2][N][N]; char s[N], t[N]; int main() { scanf("%d%d%d%s%s", &n, &m, &k, s + 1, t + 1); dp[0][0][0] = 1; for(int i = 1; i <= n; ++i) { pre ^= 1; dp[pre][0][0] = 1; for(int j = 1; j <= min(m, i); ++j) for(int x = 1; x <= min(j, k); ++x) { dp[pre][j][x] = f[pre][j][x] = 0; if(s[i] == t[j]) f[pre][j][x] = (f[pre ^ 1][j - 1][x] + dp[pre ^ 1][j - 1][x - 1]) % mod; dp[pre][j][x] = (f[pre][j][x] + dp[pre ^ 1][j][x]) % mod; } } printf("%d\n", dp[pre][m][k]); return 0; }