HDU - 6357 Hills And Valleys DP 最长上升子序列

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

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/81674002