• HDU


    http://acm.hdu.edu.cn/showproblem.php?pid=6357

    题意

    给一个数值范围为0-9的a数组,可以选择翻转一个区间,问非严格最长上升子序列,以及翻转的区间。

    分析

    官方题解的做法:

    它把最长不下降子序列映射成两个序列的最长公共子序列问题 
    a序列就是给出的原序列 
    b序列是值域的序列 
    需要注意的是:b序列可以重复匹配

    一般的最长不下降子序列中,b序列就是:0,1,2,3,4,5,6,7,8,9 
    这样a和b的最长公共子序列就是一个最长不下降子序列。

    然后这题它说可以翻转一次。我们发现如果在a序列中枚举翻转端点是很难实现的。但可以在b序列上枚举翻转端点(最多C(10,2)种方案)。 
    换句话说,我们可以枚举翻转的两个端点的值。 
    然后,b序列可以转化成这个样子: 
    假设我们枚举的翻转的左端点值为y,右端点值为x,满足x<y 
    b序列就可以变成: 
    0,1,2,x1,x,(y,y1,y2,x+1,x),y,y+1,8,

    其中括号内的部分可以通过翻转使得整个串仍然是一个0到9的不下降序列。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,t;
    char s[MAXN];
    int b[MAXN],spl,spr,ansl,ansr;
    int dp[MAXN][22],tl[MAXN][22],tr[MAXN][22];;
    int solve(int cnt){
        for(int i=0;i<cnt;i++) dp[0][i]=0;
        for(int i=1;i<=n;i++)
            for(int j=0;j<cnt;j++){
                dp[i][j]=dp[i-1][j];
                tl[i][j]=tl[i-1][j];
                tr[i][j]=tr[i-1][j];
                if(s[i]==b[j]){
                    dp[i][j]++;
                    if(spl==j&&tl[i][j]==0)
                        tl[i][j]=i;
                    if(spr==j)
                        tr[i][j]=i;
                }
                if(dp[i][j-1]>dp[i][j]){
                    dp[i][j]=dp[i][j-1];
                    tl[i][j]=tl[i][j-1];
                    tr[i][j]=tr[i][j-1];
                }
            }
        return dp[n][cnt-1];
    }
    int main(){
        int t;
        scanf("%d",&t);    
        while(t--){
            scanf("%d",&n);
            scanf("%s",s+1);
            int minl=9;
            int maxl=0;
            for(int i=1;i<=n;i++){
                s[i]-='0';
                maxl=max(maxl,int(s[i]));
                minl=min(minl,int(s[i]));
            }
            for(int i=0;i<10;i++)
                b[i]=i;
            int ans=solve(10);
            ansl=1;
            ansr=1;
            for(int l=minl;l<=maxl;l++)
                for(int r=minl;r<l;r++){
                    int cnt=0;
                    for(int i=0;i<=r;i++)
                        b[cnt++]=i;
                    spl=cnt;
                    for(int i=l;i>=r;i--)
                        b[cnt++]=i;
                    spr=cnt-1;
                    for(int i=l;i<10;i++)
                        b[cnt++]=i;
                    int ans1=solve(cnt);
                    if(ans1>ans&&tl[n][cnt-1]&&tr[n][cnt-1]){
                        ans=ans1;
                        ansl=tl[n][cnt-1];
                        ansr=tr[n][cnt-1];  
                    }
                }
            printf("%d %d %d
    ",ans,ansl,ansr);
        }
        return 0;
    }
  • 相关阅读:
    SQLServer多表联查,多表分页查询
    GOF23种设计模式概括
    常用的正则表达式
    面向对象七大原则
    Jquery简单学习
    MVC图片上传详解
    面向对象OOP概念描述
    C++ 基础命名空间 using namespace std;
    找不到WJSWDLL.dll
    AspectJ中的类型间声明(成员注入)
  • 原文地址:https://www.cnblogs.com/fht-litost/p/9557263.html
Copyright © 2020-2023  润新知