Hills And Valleys

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

 

这道题的简化版

 

#include<bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)

const int maxn=1e5+10;
char str[maxn];

int dp[maxn][20],tl[maxn][20],tr[maxn][20];

int n;

/*
原串:0012
模版串:     012
dp[i][j]代表 原串的前i个字符和模版串的前j个字符的最大匹配结果

思想:枚举反转权值的所有情况  C(10,2),将求最长上升子序列转换为求 (可重复的)最长公共子序列 (注意转移方程)
枚举原串是不可能的,只能枚举反转模版串(权值串)的所有情况


*/
int bit[100];
int solve(int L,int R,int cnt){
   // memset(tl,0,sizeof(tl));
   // memset(tr,0,sizeof(tr));
    rep(i,0,cnt+1)dp[0][i]=0;
    rep(i,1,n+1){
        rep(j,1,cnt+1){
/*
            dp[i][j]=dp[i-1][j];
            tl[i][j]=tl[i-1][j];
            tr[i][j]=tr[i-1][j];
            if(str[i]-'0'==bit[j]){
                dp[i][j]++;
                if(L==j&&tl[i][j]==0)
                    tl[i][j]=i;
                if(R==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];
            }
*/
            if(str[i]-'0'==bit[j]){
                dp[i][j]=dp[i-1][j]+1;
                tl[i][j]=tl[i-1][j];
                tr[i][j]=tr[i-1][j];
                if(j==L&&tl[i][j]==0)tl[i][j]=i;
                if(j==R)tr[i][j]=i;
               // printf("i:%d L:%d R:%d tl:%d tr:%d\n",i,L,R,tl[i][j],tr[i][j]);
            }
            else{
                if(dp[i-1][j]>dp[i][j-1]){
                    dp[i][j]=dp[i-1][j];
                    tl[i][j]=tl[i-1][j];
                    tr[i][j]=tr[i-1][j];
                }
                else{
                    dp[i][j]=dp[i][j-1];
                    tl[i][j]=tl[i][j-1];
                    tr[i][j]=tr[i][j-1];
                }
            }
        // printf("i:%d j:%d dp:%d\n",i,j,dp[i][j]);
        }
    }
    return dp[n][cnt];
}



int main(){
    //freopen("123.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        scanf(" %s",str+1);
        rep(i,0,10)bit[i+1]=i;

        int ans=solve(-1,-1,10);
        //printf("ans:%d\n",ans);
        int min_v=9,max_v=0;
        rep(i,1,n+1)min_v=min(min_v,str[i]-'0'),max_v=max(max_v,str[i]-'0');
        int ansl=1,ansr=1;
        rep(L,min_v,max_v+1){
            rep(R,L+1,max_v+1){
                //标记模版长度,左端点位置,右端点的位置
                int cnt=0,pos_l,pos_r;
                rep(i,min_v,L+1)bit[++cnt]=i;
                pos_l=cnt+1;
                per(i,L,R+1)bit[++cnt]=i;
                pos_r=cnt;
                rep(i,R,max_v+1)bit[++cnt]=i;

                int ans_tmp=solve(pos_l,pos_r,cnt);
                //printf("ans_tmp:%d\n",ans_tmp);
                //可能不存在,即tl,tr为0
                if(ans_tmp>ans&&tl[n][cnt]&&tr[n][cnt]){
                    ans=ans_tmp;
                    ansl=tl[n][cnt];
                    ansr=tr[n][cnt];
                   //rep(i,1,cnt+1)printf("%d%c",bit[i],i==cnt?'\n':' ');
                  // printf("l:%d r:%d ans:%d L:%d R:%d\n",ansl,ansr,ans,L,R);
                }
            }
        }
        printf("%d %d %d\n",ans,ansl,ansr);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值