2018多校集训 H. Hills And Valleys
传送门
题意
给你一个\(n \leq 10^5\)的序列,数字都是0-9,你可以任意翻转一个子区间,问翻转后最长不降子序列的最大长度。
题解
简略题解:我开始考虑的是\(f_i,j,k\)表示的是翻转\(i\)结尾的区间,翻转区间贡献了最长不降序列中\(j\)到\(k\)的部分, 那么只要新加入的数小于\(j\)就可以翻过去,大于\(k\)就可以补到后面,但其实有问题,因为你不知道翻转区间之前的区间贡献的范围,所以要记录\(f_i,j,k,l\)多一个状态表示翻转区间之前贡献了\(1-l\),但这样会爆炸空间,我不知道能不能滚动数组,我最后考虑使用性质优化:对于一个翻转区间, 如果区间端点不是贡献最小值,或者贡献最大值,也就是端点不参与贡献,那么翻转一个更小不包括端点的区间必然更优。所以我们考虑直接使得右端点是最大值,那么就可以少存一位,然后枚举上一个最大值就好了,对于每一个最大值,只枚举最近的一个数就好了。
实现
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
int read(){
int num=0, flag=1; char c=getchar();
while(!isdigit(c) && c!='-') c=getchar();
if(c == '-') flag=-1, c=getchar();
while(isdigit(c)) num=num*10+c-'0', c=getchar();
return num*flag;
}
int readc(){
char c=getchar();
while(!isdigit(c)) c=getchar();
return c-'0';
}
const int N = 1e5+1000;
const int M = 10;
int n, T;
int a[N];
int f[N][M][M], L[N][M][M];
int g[N][M];
int h[N][M];
int las[N][M];
int main(){
T = read();
while(T--){
n = read();
for(int i=1; i<=n; i++) a[i]=readc();
for(int i=1; i<=n; i++){
for(int j=0; j<M; j++) las[i][j] = las[i-1][j];
if(i != 1) las[i][a[i-1]] = i-1;
}
for(int i=0; i<=n+1; i++){
for(int j=0; j<M; j++){
g[i][j] = 0;
h[i][j] = 0;
for(int k=0; k<M; k++){
f[i][j][k] = 0;
}
}
}
for(int i=1; i<=n; i++){
for(int j=0; j<M; j++){
g[i][j] = g[i-1][j];
if(a[i] <= j) g[i][j] = max(g[i][j], g[i-1][a[i]] + 1);
}
}
for(int i=1; i<=n; i++){
for(int j=0; j<M; j++){
for(int k=j; k<M; k++){
f[i][j][k]=0,L[i][j][k]=i;
if(a[i]<=k && a[i]>=j) {
f[i][j][k]=g[i-1][j]+1;
for(int l=k; l>=a[i]; l--){
int nex = las[i][l];
int res=f[nex][j][k]+1;
if(res>f[i][j][k]) f[i][j][k]=res, L[i][j][k]=L[nex][j][k];
}
}
}
}
}
for(int i=n; i>=1; i--){
for(int j=0; j<M; j++){
h[i][j] = h[i+1][j];
if(a[i] >= j){
h[i][j] = max(h[i][j], h[i+1][a[i]]+1);
}
}
}
int ans=0, ansl=1, ansr=1;
for(int i=1; i<=n; i++){
for(int j=0; j<M; j++){
for(int k=j; k<M; k++){
if(f[i][j][k] + h[i+1][k] > ans){
ans=f[i][j][k] + h[i+1][k], ansl=L[i][j][k], ansr=i;
}
}
}
}
printf("%d %d %d\n", ans, max(1, ansl), ansr);
// printf("%d\n", ans);
}
return 0;
}
/*
1
9
203258468
*/