HDU 6357 Hills And Valleys 【LCS+思维】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hhhhhhxh/article/details/81671992

题目链接

题意:给一串数(长度<=1e5),翻转其中的一段区间,使得翻转后这串数的最长不下降子序列的长度最大。求最大的长度以及翻转的区间的左右端点。

明显不可能遍历所有的子区间……但是里面的每个数都只有0到9,因此可以枚举翻转的区间的左右端点的值。例如左端点的值是L,右端点的值是R,那么求出原串和0,1,2,…,L,(R,R-1,..,L),R,R+1,…,9这个模式串的LCS。维护最大长度就可以得到答案。

比较麻烦的是怎么求翻转区间的左右端点。我们记录上面说的模式串中翻转位置的左右端点。在LCS处理到这两个端点的值的时候考虑如何转移。可以通过 L [ i ] [ j ] R [ i ] [ j ] 两个数组来维护翻转区间的最左端点和最右端点。如果a[i]==b[j],那么i就是翻转区间的端点。否则的话就是从另一个状态转移过来的,直接继承那个状态的值。

注意在更新的时候还要判断左右端点是否存在……

附赠一道这题的简化版本:Codeforces Round #462 (Div. 2): C. A Twisty Movement

#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+5;

char s[maxn]; 
int T,n,a[maxn],b[15],dp[maxn][15],L[maxn][15],R[maxn][15],spl=0,spr=0;

void lcs(int len1,int len2){
//  dp[i][j]=max(dp[i-1][j]+(a[i]==b[j]),dp[i][j-1]);
    for (int i=1;i<=len2;i++){
        dp[0][i]=0;
    }
    for (int i=1;i<=len1;i++){
        for (int j=1;j<=len2;j++){
            dp[i][j]=dp[i-1][j];
            L[i][j]=L[i-1][j];
            R[i][j]=R[i-1][j];
            if (a[i]==b[j]){
                dp[i][j]++;
                if (L[i][j]==0&&j==spl){
                    L[i][j]=i;
                }
                if (j==spr){
                    R[i][j]=i;
                }
            }
            if (dp[i][j-1]>dp[i][j]){
                dp[i][j]=dp[i][j-1];
                L[i][j]=L[i][j-1];
                R[i][j]=R[i][j-1];
            }
        }
    }
}

void show(int len1,int len2){
    printf("a:\n");
    for (int i=1;i<=len1;i++){
        printf("%d ",a[i]);
    }
    printf("\nb:\n");
    for (int i=1;i<=len2;i++){
        printf("%d ",b[i]);
    }
    printf("\n");
}

int main(){
#ifdef __APPLE__
    //freopen("1.in","r",stdin);
#endif
    scanf("%d",&T);
    while (T--){
        scanf("%d",&n);
        scanf("%s",s+1);
        for (int i=1;i<=n;i++){
            a[i]=s[i]-'0';
        }
        int len1=n,len2=0,ans=0,ll=0,rr=0;
        for (int i=0;i<=9;i++)  b[++len2]=i;
        lcs(len1,len2);
        ans=dp[len1][len2],ll=1,rr=1;
        for (int l=0;l<=9;l++){
            for (int r=l+1;r<=9;r++){
                len2=0;
                if (l==r)   continue;
                for (int i=0;i<=l;i++)  b[++len2]=i;
                spl=len2+1;
                for (int i=r;i>=l;i--)  b[++len2]=i;
                spr=len2;
                for (int i=r;i<=9;i++)  b[++len2]=i;
//              spl=l+2,spr=r+2;
                lcs(len1,len2);
                if (dp[len1][len2]>ans&&L[len1][len2]&&R[len1][len2]){
                    ans=dp[len1][len2];
                    ll=L[len1][len2];
                    rr=R[len1][len2];
                }
            }
        }
        if (n==1)
            ll=rr=1;
        printf("%d %d %d\n",ans,ll,rr);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hhhhhhxh/article/details/81671992
今日推荐