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
",ans);
}