HZAU校赛F题 LCS (dp)



17: LCS
Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 170  Solved: 33
[Submit][Status][Web Board]
Description

   Giving two strings consists of only lowercase letters, find the LCS(Longest Common Subsequence) whose all partition are not less than k in length.
Input

There are multiple test cases. In each test case, each of the first two lines is a string(length is less than 2100). The third line is a positive integer k. The input will end by EOF.
Output
    For each test case, output the length of the two strings’ LCS.

Sample Input
abxccdef
abcxcdef
3
abccdef
abcdef
3
Sample Output
4
6
HINT


   In the first test case, the answer is:

      abxccdef

      abcxcdef

    The length is 4.

   In the second test case, the answer is:

      abccdef

      abc def

   The length is 6
Source


题意:求两个字符串里面的LCS,这个LCS的在每个字符串里面的分割长度都要大于等于k

题解:什么叫LCS的分割长度大于等于k呢,就是在两个串里面找长度大于等于k的一样的不重叠的子串,然后长度加起来

普通的LCS是n^2的转移,但是可以不连续,这个的话每段必须要连续至少等于k

我们同样设状态dp[i][j]为到达a[i],b[j]处,这个题目要求的LCS是多少

想想如果a[i]!=b[j],dp[i][j]=max(dp[i-1][j],dp[i][j-1]),是这没有问题的,如果a[i]==b[j]呢,这会就得考虑要不要取这个相等了,如果不取和前面一样,如果要取,那么往前至少得连续k个,开头我想的n^3的方法,就是往前找k个,但是这样不太靠谱,肯定TLE

所以需要预处理出来a[i]b[j]往前有多少个相同的,记为f[i][j],这个O(n^2)预处理就行了,然后就是如果a[i]==b[j],并且f[i][j]>=k的时候,你可以连续取k个,也可以连续取f[i][j]个,为什么呢,假如你连续k+1个,k>1,然后你取k个,前面连续的不满k个,就直接为0了,所以这时你需要取f[i][j]个,但是可能前面这f[i][j]个不需要连续取,取k个即可能有更有解,所以也能取k个,所以转移为dp[i][j]=max(max(dp[i-1][j],dp[i][j-1]),max(dp[i-k][j-k]+k,dp[i-f[i][j]][j-f[i][j]]+f[i][j]))


#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           2105
#define   MAXN          1000005
#define   maxnode       10
#define   sigma_size    2
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
const double inf   = 1e18;
const double eps   = 1e-9;
const LL     mod   = 1e9+7;
const ull    mxx   = 1333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

char a[MAX],b[MAX];
int dp[MAX][MAX];
int f[MAX][MAX];

int main(){
    //freopen("in.txt","r",stdin);
    int k;
    while(~scanf("%s%s%d",a+1,b+1,&k)){
        int n=strlen(a+1),m=strlen(b+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i]==b[j]){
                    f[i][j]=f[i-1][j-1]+1;
                }
                else f[i][j]=0;
            }
        }
        mem(dp,0);
        for(int i=k;i<=n;i++){
            for(int j=k;j<=m;j++){
                if(f[i][j]>=k){
                    dp[i][j]=max(max(dp[i-1][j],dp[i][j-1]),max(dp[i-f[i][j]][j-f[i][j]]+f[i][j],dp[i-k][j-k]+k));
                }
                else{
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
                //cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
            }
        }
        cout<<dp[n][m]<<endl;
    }
    return 0;
}

你可能感兴趣的:(HZAU校赛F题 LCS (dp))