hdu 6357 (求一个序列对另一个序列的最长可重复公共子序列)

Hills And Valleys

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 894    Accepted Submission(s): 279
Special Judge

 

Problem Description

Tauren has an integer sequence A of length n (1-based). He wants you to invert an interval [l,r] (1≤l≤r≤n) of A (i.e. replace Al,Al+1,⋯,Ar with Ar,Ar−1,⋯,Al) to maximize the length of the longest non-decreasing subsequence of A. Find that maximal length and any inverting way to accomplish that mission.
A non-decreasing subsequence of A with length m could be represented as Ax1,Ax2,⋯,Axm with 1≤x1<x2<⋯<xm≤n and Ax1≤Ax2≤⋯≤Axm.

 

 

Input

The first line contains one integer T, indicating the number of test cases.
The following lines describe all the test cases. For each test case:
The first line contains one integer n.
The second line contains n integers A1,A2,⋯,An without any space.
1≤T≤100, 1≤n≤105, 0≤Ai≤9 (i=1,2,⋯,n).
It is guaranteed that the sum of n in all test cases does not exceed 2⋅105.

 

 

Output

For each test case, print three space-separated integers m,l and r in one line, where m indicates the maximal length and [l,r] indicates the relevant interval to invert.

 

 

Sample Input

 

2 9 864852302 9 203258468

 

 

Sample Output

 

5 1 8 6 1 2

Hint

In the first example, 864852302 after inverting [1, 8] is 032584682, one of the longest non-decreasing subsequences of which is 03588. In the second example, 203258468 after inverting [1, 2] is 023258468, one of the longest non-decreasing subsequences of which is 023588.

 

 

Source

2018 Multi-University Training Contest 5

 

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6373 6372 6371 6370 6369 

代码: 

#include<bits/stdc++.h>

using namespace std;
const int N =1e5+5;
int dp[N][15];
int b[12];
char s[N];
int a[N];
int maxx,minn;
int lt[N][15],rt[N][15];
int ansl,ansr;
int bl,br;
int n;

void jiaohuan(int l,int 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;
}

int getdp()
{
    for(int i=0;i<=n;i++){
        for(int j=0;j<=12;j++){
            dp[i][j]=0; lt[i][j]=rt[i][j]=0;
        }
    }

    for(int i = 1;i<= n;i++)
	{
		for(int j = 1;j<=12;j++)
		{
			dp[i][j] = dp[i-1][j];
			rt[i][j] = rt[i-1][j];
			lt[i][j] = lt[i-1][j];

			if(a[i] == b[j])
			{
				dp[i][j]++;
				if(bl == j&&lt[i][j] == 0)
                    lt[i][j] = i;
                if(br == j)
                    rt[i][j] = i;
			}


			if(dp[i][j-1]> dp[i][j])
			{
				dp[i][j] = dp[i][j-1];
				rt[i][j] = rt[i][j-1];
				lt[i][j] = lt[i][j-1];
			}
		}
	}

    /*

    for(int i=1;i<=n;i++){
        for(int j=1;j<=12;j++){
            cout<<dp[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<"**** "<<endl;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=12;j++){
            cout<<lt[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<"**** "<<endl;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=12;j++){
            cout<<rt[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<"**** "<<endl;
    */

    return dp[n][12];
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        scanf("%s",s+1);
        maxx=-1; minn=15;
        for(int i=1;i<=n;i++){
            a[i]=s[i]-'0';
            maxx=max(a[i],maxx);
            minn=min(a[i],minn);
        }
        for(int i=0;i<=9;i++) b[i+1]=i;

        int ans=getdp();
        ansl=1; ansr=1;

        for(int i=minn;i<=maxx;i++){
            for(int j=i+1;j<=maxx;j++){
                jiaohuan(i,j);
                bl=i+2; br=j+2; /// 记录翻转区间在b数组中的位置
                int tmp=getdp();
                if(tmp>ans){
                    ans=tmp;
                    if(lt[n][12]!=0&&rt[n][12]!=0){
                        ansl=lt[n][12];
                        ansr=rt[n][12];
                    }
                }
            }
        }
        printf("%d %d %d\n",ans,ansl,ansr);

    }
    return 0;
}

/*

1
12
123335435557

*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值