Codeforces Round #358 (Div. 2) DP

http://www.codeforces.com/problemset/problem/682/D

 

题意:最长公子序列,限制是最多分成k段,也就是你得到的最长公子序列不能实在原串中分成K段以上。

 

思路:一个DP。。想了很久。。果然DP始终没法入门。。我们设状态是DP[ i ] [ j ] [ k ] [ s ]   表示匹配到第i,j时分成k段,此时是连续或不连续时的最长LCS。。

类比LCS的转移方法。。最关键的就是最后一个状态S的处理。。。

s[i] != t[j] 时。。显然  DP【x】【y】【z】【0】的转移和普通的LCS没什么区别,因为当前位置都不匹配,所以DP【x】【y】【z】【1】显然是0了。。

当 s[i] == t[j]时。。显然不连续的部分转移依旧很简单没什么好说的。。连续的时候就要注意了。。首先他可能从k-1来也可能从k来,从k-1来的话那有必然从【k-1】【0】来。。这么说的话思路就很清晰了。。于是愉快的水过去。。。

 

代码:

 

 

#include <bits/stdc++.h>

using namespace std;
const int maxn=1001;

char s[maxn];
char t[maxn];
int dp[maxn][maxn][11][2];

int main(){
    int n,m,lim;
    scanf("%d%d%d",&n,&m,&lim);
    scanf("%s%s",s,t);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            for(int k=1;k<=lim;k++){
                if(s[i]==t[j]){
                    int a,b;
                    a=dp[i][j][k][1]+1;
                    b=max(dp[i][j+1][k-1][0],max(dp[i+1][j][k-1][0],dp[i][j][k-1][0]+1));
                    dp[i+1][j+1][k][1]=max(a,b);
                    a=max(dp[i][j+1][k][1],dp[i+1][j][k][1]);
                    b=max(dp[i][j+1][k][0],dp[i+1][j][k][0]);
                    dp[i+1][j+1][k][0]=max(a,b);
                }
                else{
                    int a,b;
                    a=max(dp[i][j+1][k][1],dp[i+1][j][k][1]);
                    b=max(dp[i][j+1][k][0],dp[i+1][j][k][0]);
                    dp[i+1][j+1][k][0]=max(a,b);
                    dp[i+1][j+1][k][1]=0;
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=1;k<=lim;k++){
                ans=max(ans,max(dp[i][j][k][0],dp[i][j][k][1]));
            }
        }
    }
    printf("%d\n",ans);
}


 

posted @ 2016-07-31 18:32  zhangxianlong  阅读(82)  评论(0编辑  收藏  举报