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\n",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\n",ans,ansl,ansr);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/zquzjx/p/10333418.html
今日推荐