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.
题意
给你一个数组a, 0 <= a[i] <= 9。 现在你需要翻转一个区间使得最长非下降子序列最长。
题解
如果不用翻转,那么是个简单的dp。设dp[i][j]表示前i个数,最后一位是j的最长上升子序列。
现在要翻转,那么我们设置dp[i][j][k][l]表示前i位,最后一位是j,翻转区间上届是k下届是l的最长长度。
预处理出pre[i][j]和suf[i][j]分别表示 前i位最后一位 和 后i位最前一位是j 的最长上升序列长度。
转移方程具体见代码
代码
#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define debug(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int mod = 1 << 30;
const int MAXN = 1e5 + 5;
char s[MAXN];
int pre[MAXN][11], suf[MAXN][11];
int d[2][11][11][11], pos[2][11][11][11];
void update(int t, int a, int b, int c, int v, int p) {
if(v >= d[t][a][b][c]) d[t][a][b][c] = v, pos[t][a][b][c] = p;
}
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
#endif
int T;
cin >> T;
while(T--) {
int n;
scanf("%d %s", &n, s + 1);
for(int i = 1; i <= n; i++) s[i] -= '0';
for(int i = 0; i < 10; i++) suf[n + 1][i] = 0;
for(int i = 1; i <= n; i++)
for(int j = 0; j <= 9; j++)
pre[i][j] = max(j ? pre[i][j - 1] : 0, pre[i - 1][j] + (s[i] == j));
for(int i = n; i >= 1; i--)
for(int j = 9; j >= 0; j--)
suf[i][j] = max(j <= 9 ? suf[i][j + 1] : 0, suf[i + 1][j] + (s[i] == j));
int maxn = 0, l = 1, r = 1;
memset(d, 0, sizeof(d));
memset(pos, 0, sizeof(pos));
for(int i = 1; i <= n; i++) {
int now = i & 1;
memset(d[now], 0, sizeof(d[now]));
memset(pos[now], 0, sizeof(pos[now]));
for(int a = 0; a <= 9; a++) {
for(int b = a; b <= 9; b++) {
for(int c = b; c >= a; c--) {
update(now, a, b, c, d[now^1][a][b][c] + (s[i] == c), pos[now^1][a][b][c]);
if(c < b)
update(now, a, b, c, d[now][a][b][c + 1], pos[now][a][b][c + 1]);
update(now, a, b, c, pre[i - 1][a] + (s[i] == c), i);
if(maxn < d[now][a][b][c] + suf[i + 1][b]) {
maxn = d[now][a][b][c] + suf[i + 1][b];
l = pos[now][a][b][c];
r = i;
}
}
}
}
}
printf("%d %d %d\n", maxn, l, r);
}
return 0;
}