zoukankan      html  css  js  c++  java
  • hdu6537 /// DP 最长不降子序列->最长公共子序列

    题目大意:

    给定一个字符串 字符为0~9

    求翻转某个区间后使得串中的最长不降子序列最长

    因为字符范围为0~9

    假设有一个 0 1 2 3 4 5 6 7 8 9 的序列

    此时翻转某个区间得到形如 0 1 ... L【R R-1 ... L+1 L】R R+1 ... 9 的序列

    用这个序列与原串匹配一个最长公共子序列 

    题解:

    https://www.cnblogs.com/ZERO-/p/9493597.html

    https://blog.csdn.net/qkoqhh/article/details/81491097

    //#include <bits/stdc++.h>
    //using namespace std;
    //#define INF 0x3f3f3f3f
    //#define LL long long
    //#define mem(i,j) memset(i,j,sizeof(i))
    //const int N=1e5+5;
    //
    //int n, b[15];
    //char str[N]; int a[N];
    //int dp[N][15], pre[N][15]; 
    //
    //int main()
    //{
    //    int t; scanf("%d",&t);
    //    while(t--) {
    //        int ans=0,ansl,ansr; scanf("%d%s",&n,str);
    //        for(int i=0;i<n;i++) a[i+1]=str[i]-'0'; 
    //        for(int L=1;L<=9;L++)
    //            for(int R=L;R<=9;R++) { 
    //                int tot=0;
    //                for(int k=0;k<=L;k++) b[++tot]=k;
    //                for(int k=R;k>=L;k--) b[++tot]=k;
    //                for(int k=R;k<=9;k++) b[++tot]=k;
    //                for(int i=1;i<=n;i++) {
    //                    int t=0;
    //                    for(int j=1;j<=tot;j++) {
    //                        if(dp[i-1][j]>dp[i-1][t]) t=j;
    //                        pre[i][j]=t;
    //                        dp[i][j]=dp[i-1][t]+(a[i]==b[j]);
    //                    }
    //                } 
    //                for(int j=tot;j>=1;j--)
    //                    if(dp[n][j]>ans) {
    //                        ans=dp[n][j];
    //                        int t=j,l=0,r=0;
    //                        for(int i=n;i>=0;i--) {
    //                            if(!l && t<=L+1) l=i+1;
    //                            if(!r && t<=R+2) r=i;
    //                            t=pre[i][t];
    //                        }
    //                        if(r==0) r=l;
    //                        ansl=l,ansr=r;
    //                    } 
    //            }
    //        printf("%d %d %d
    ",ans,ansl,ansr);
    //    }
    //
    //    return 0;
    //}
    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define LL long long
    #define mem(i,j) memset(i,j,sizeof(i))
    const int N=1e5+5;
    
    int n, b[15];
    char str[N]; int a[N];
    int dp[N][15], pre[N][15];
    
    int main(){
        int t; scanf("%d",&t);
        while(t--) {
            int ansl,ansr,ans=0; scanf("%d%s",&n,str);
            for(int i=0;i<n;i++) a[i+1]=str[i]-'0';
            for(int L=0;L<=9;L++) /// 枚举翻转区间
                for(int R=L;R<=9;R++) {
                    int tot=0;
                    for(int i=0;i<=L;i++) b[++tot]=i;
                    for(int i=R;i>=L;i--) b[++tot]=i;
                    for(int i=R;i<=9;i++) b[++tot]=i;
                    for(int i=1;i<=n;i++) {
                        int t=0;
                        for(int j=1;j<=tot;j++) {
                            if(dp[i-1][j]>dp[i-1][t]) t=j;
                            pre[i][j]=t; // 记录前驱在b[]中的位置 
                            dp[i][j]=dp[i-1][t]+(a[i]==b[j]); // 更新LCS长度
                        }
                    }
                    for(int j=tot;j>=1;j--)
                        if(dp[n][j]>ans) {
                            ans=dp[n][j];
                            int t=j,l=0,r=0;
                            for(int i=n;i>=0;i--) {
                                // 翻转区间为 0 1 ... L【R R-1 ... L+1 L】R R+1 ... 9
                                // 所以区间左端l位置实际是在L+1
                                // 所以区间右端r位置实际是在R+2 
                                if(!l && t<=L+1) l=i+1;
                                if(!r && t<=R+2) r=i; 
                                // 当t满足位置条件 才是找到l r
                                t=pre[i][t];
                            }
                            if(r==0)r=l;
                            ansl=l; ansr=r;
                        }
                }
            printf("%d %d %d
    ",ans,ansl,ansr);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Retrofit2源码分析
    Android8.0硬件加速的重绘流程
    Android单元测试
    rand5->rand7,rand7->rand10
    快速排序的随机化版本
    快速排序
    亦或实现交换
    在最坏情况下,找到n个元素中第二小的元素需要n+lgn-2次比较
    3*n/2时间内求出最大最小值
    基数排序
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10333418.html
Copyright © 2011-2022 走看看