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);
}
}