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): 146    Accepted Submission(s): 47
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≤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.

Sample Input

2 9 864852302 9 203258468

Sample Output

5 1 8 6 1 2

Hint

In the first example, 864852302 after inverting [1, 8] is 032584682, one of the longest non-decreasing subsequences of which is 03588. In the second example, 203258468 after inverting [1, 2] is 023258468, one of the longest non-decreasing subsequences of which is 023588.

 

 

传送门:HDU-6357

题意:给出一个只有0~9的序列,可以选择翻转一个区间,要求求出最大的不下降子序列长度,并输出翻转的区间。

题解:多校时搞了个N*10^3的算法不敢写。。。结果没优化常数就780ms过了。。。

设dp[i][x][y][z][0/1/2]为,翻转的区间中最大值为x,最小值为y,当前遍历到第i个数字,子序列最后一个数字为z时,最长子序列长度。其中0表示当前的数字在翻转的区间前面,1表示当前的数字在需要翻转的区间内,2表示当前的数字在翻转的区间后面。这样就可以很轻松的想到转移方程。

比较有难度的是第二问,即要输出翻转的是哪个区间。

考虑到,当状态从0->1,1->2时所选的是第几个数字是很容易维护的,因此可以维护2个数组,a数组表示从0->1时所选的第一个数字的下标,b数组表示从1->2时所选的第一个数字的下标,那么翻转的区间就是[a,b-1]

有个坑点是题目要求必须翻转,当不选择翻转的时候,可以选择翻转一个数字即可。

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define FIN freopen("in.txt","r",stdin);
using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int mod = 1 << 30;
const int MX = 1e5 + 5;

int dp[2][10][3];
int a[2][10][3];
int b[2][10][3];
char s[MX];

void solve() {
    int n;
    scanf("%d", &n);
    scanf("%s", s + 1);
    int ans = 0, l = 0, r = 0;
    rep(x, 0, 10) rep(y, 0, x + 1) {
        memset(dp, 0, sizeof(dp));
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        rep(i, 1, n + 1) {
            int now = s[i] - '0';
            int cur = i & 1, pre = cur ^ 1;
            rep(z, 0, y + 1) dp[cur][z][0] = dp[pre][z][0];
            rep(z, y, x + 1) dp[cur][z][1] = dp[pre][z][1], a[cur][z][1] = a[pre][z][1];
            rep(z, x, 10)    dp[cur][z][2] = dp[pre][z][2], a[cur][z][2] = a[pre][z][2], b[cur][z][2] = b[pre][z][2];
            if(now <= y) rep(z, 0, now + 1) {
                if(dp[cur][now][0] < dp[pre][z][0] + 1) {
                    dp[cur][now][0] = dp[pre][z][0] + 1;
                }
            }
            if(y <= now && now <= x) rep(z, 0, y + 1) {
                if(dp[cur][now][1] < dp[pre][z][0] + 1) {
                    dp[cur][now][1] = dp[pre][z][0] + 1;
                    a[cur][now][1] = i;
                }
            }
            if(y <= now && now <= x) rep(z, now, x + 1) {
                if(dp[cur][now][1] < dp[pre][z][1] + 1) {
                    dp[cur][now][1] = dp[pre][z][1] + 1;
                    a[cur][now][1] = a[pre][z][1];
                }
            }
            if(now >= x) rep(z, y, x + 1) {
                if(dp[pre][z][1] && dp[cur][now][2] < dp[pre][z][1] + 1) {
                    dp[cur][now][2] = dp[pre][z][1] + 1;
                    a[cur][now][2] = a[pre][z][1];
                    b[cur][now][2] = i - 1;
                }
            }
            if(now >= x) rep(z, x, now + 1) {
                if(dp[pre][z][2] && dp[cur][now][2] < dp[pre][z][2] + 1) {
                    dp[cur][now][2] = dp[pre][z][2] + 1;
                    a[cur][now][2] = a[pre][z][2];
                    b[cur][now][2] = b[pre][z][2];
                }
            }
            rep(z, 0, 10) rep(k, 0, 3) {
                if(ans < dp[cur][z][k]) {
                    ans = dp[cur][z][k];
                    if(k == 0) l = r = 1;
                    else if(k == 1) l = a[cur][z][k], r = i;
                    else l = a[cur][z][k], r = b[cur][z][k];
                }
            }
        }
    }
    printf("%d %d %d\n", ans, l, r);
}


int main() {
    //freopen("in.txt", "r", stdin);
    int T;
    for(cin >> T; T; T--) solve();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值