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的序列。這很明顯。轉移方程為:
然後就是維護[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的位置,即可求出答案。轉移方程:
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);
}
}