1. 程式人生 > >HDU 6357 Hills And Valleys 【DP】

HDU 6357 Hills And Valleys 【DP】

Hills And Valleys

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 296    Accepted Submission(s): 98
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≤10^5, 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

題意:給定一個長度為n(n<=1e5)只包含‘0’~‘9’的字串,你可以翻轉[l,r]的區間,然後求它的最長不下降子序列的長度的最大值,並求出翻轉區間。

分析:這個題比賽時想啦好久,一點思路也沒有,後來看啦杜教的講解和程式碼,才稍微有點懂啦。感覺這個DP很巧妙,我果然對DP一無所知。因為翻轉區間[l,r],則這段最長不下降子序列翻轉前構成為1*2*3*...X*【Y*(Y-1)*...X*】 Y*(Y+1)*...9*。(x*表示長度大於等於0的完全由x組成的串)。然後我們首先要預處理一下到第i個位置,最大字元為j的不下降子序列的長度設為dp[i][j]和反向的最長不上升子序列。對於dp[i][j],它可以有dp[i-1][j]和dp[i][j-1]得到。即前i-1個最大字元為j的序列,和前i個最大字元為j-1的序列。這很明顯。轉移方程為:

dp[i][j]=max(dp[i-1][j]+(s[i]==j),dp[i][j-1]);

然後就是維護[l,r]的值,這就很麻煩,僅僅列舉[l,r]區間就會T。其實可以維護[1,r]區間即1*2*3*..X*Y*(Y-1)*...X*的最大值。

我們設f[i][x][y][z]前i個字元中序列為1*2*3*...x*y*...z*(z>=x)的最大長度,並記錄一下最左邊一個y的位置,即可求出答案。轉移方程:

f[i][x][y][z]=max\left\{f[i-1][x][y][z]+(s[i]==j),f[i][x][y][z+1](z<y),dp[i][x]\righ\};

Code

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int dp[N][10],dr[N][10];
int f[2][10][10][10],pos[2][10][10][10];
char s[N];
int main()
{
    int TA,ans,n,l,r,res;
    scanf("%d",&TA);
    while(TA--)
    {
        scanf("%d %s",&n,s+1);
        ans=0;
        for(int i=1; i<=n; i++)s[i]-='0';
        for(int j=0; j<=9; j++)dr[n+1][j]=0;

        for(int i=1; i<=n; i++)
            for(int j=0; j<=9; j++)
                dp[i][j]=max(dp[i-1][j]+(s[i]==j),j?dp[i][j-1]:0);

        for(int i=n; i>=1; i--)
            for(int j=9; j>=0; j--)
                dr[i][j]=max(dr[i+1][j]+(s[i]==j),j!=9?dr[i][j+1]:0);

        memset(f,0,sizeof(f));
        memset(pos,-1,sizeof(pos));

        for(int i=1; i<=n; i++)
        {
            int now=i&1,pre=now^1;
            memset(f[now],0,sizeof(f[now]));
            memset(pos[now],-1,sizeof(pos[now]));

            for(int x=0; x<=9; x++)
                for(int y=0; y<=9; y++)
                    for(int z=y; z>=x; z--)
                    {
                        res=f[pre][x][y][z]+(s[i]==z);
                        if(res>f[now][x][y][z])
                        {
                            f[now][x][y][z]=res;
                            pos[now][x][y][z]=pos[pre][x][y][z];
                        }
                        if(z<y)
                        {
                            res=f[now][x][y][z+1];
                            if(res>f[now][x][y][z])
                            {
                                f[now][x][y][z]=res;
                                pos[now][x][y][z]=pos[now][x][y][z+1];
                            }
                        }
                        res=dp[i][x];
                        if(res>f[now][x][y][z])
                        {
                            f[now][x][y][z]=res;
                            pos[now][x][y][z]=i+1;
                        }
                    }
            for(int x=0; x<=9; x++)
                for(int y=0; y<=9; y++)
                    for(int z=y; z>=x; z--)
                    {
                        res=f[now][x][y][z]+dr[i+1][y];
                        if(res>ans)
                        {
                            ans=res;
                            l=pos[now][x][y][z];
                            r=i;
                        }

                    }
        }
        if(l==-1)l=1;
        printf("%d %d %d\n",ans,l,r);

    }
}