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;
}
View Code

 

posted @ 2017-07-15 21:04  19992147  阅读(143)  评论(0编辑  收藏  举报