2018 Multi-University Training Contest 5 1008 / hdu6357 Hills And Valleys LCS,思维

Hills And Valleys

题意:
给出长度为 n 的数字串,要你选定一个区间 [l,r] 并翻转这个区间内的所有数字,翻转后使得最长非递减子序列的长度最大。求出长度、翻转的区间 [l,r] 。
1<=l<=r<=n。
官方题解:
枚举 [x,y] 表示翻转区间 [l,r] 中对答案产生贡献的数字所处值域,然后找出 A 最长的类似0\∗1\∗⋯x\∗y\∗(y−1)\∗⋯x\∗y\∗(y+1)\∗⋯9\∗ 的子序列,其中 k\∗ 表示任意非负整数个 k。

参考了大佬的题解https://blog.csdn.net/qq_34454069/article/details/81475646
1、因为只有10 个数字,所以可以把求最长非递减子序列 转为 求原序列与 序列{0,1,2.......8,9} 的最长公共子序列。注:第二个序列可以重复使用。
2、把翻转区间转化为枚举数字值域[x,y],翻转就可以在第二个序列里翻转。即翻转 [x,y],第二个序列就变为了 {0,1,2..x, y,y-1,y-2....x+1,x, y,y+1.....9} ,然后再求LCS。
3、要求的翻转区间 [l,r] ,我们在求 LCS 时记录即可。

好像也可以 dp 写。。。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 100005, M = 15;

int dp[N][M], tl[N][M], tr[N][M];
int n, m, ans, ansl, ansr;
int spl, spr;
char s[N], A[N];
void solve()
{
    rep(j,0,m) dp[0][j] = 0;
    rep(i,1,n) rep(j,1,m)
    {
        dp[i][j] = dp[i-1][j], tl[i][j] = tl[i-1][j], tr[i][j] = tr[i-1][j];
        if(s[i] == A[j]) {
            ++dp[i][j];
            if(j==spl && tl[i][j]==0) tl[i][j] = i;
            if(j==spr) tr[i][j] = i;
        }
        if(dp[i][j] < dp[i][j-1]) {
            dp[i][j] = dp[i][j-1], tl[i][j] = tl[i][j-1], tr[i][j] = tr[i][j-1];
        }
    }
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        int chMin=9, chMax=0;
        scanf("%d%s", &n, s+1);

        m = 9;
        rep(i,0,m) A[i] = '0'+i;
        solve();
        ans = dp[n][m], ansl = ansr = 1;

        rep(low,0,9) rep(up,low,9)
        {
            m = 0;
            rep(i,0,low) A[++m] = '0'+i;
            spl = m+1;
            per(i,up,low) A[++m] = '0'+i;
            spr = m;
            rep(i,up,9) A[++m] = '0'+i;
            solve();
            if(ans<dp[n][m] && tl[n][m] && tr[n][m])
                ans = dp[n][m], ansl = tl[n][m], ansr = tr[n][m];
        }
        printf("%d %d %d\n", ans, ansl, ansr);
    }

    return 0;
}
posted @ 2018-08-09 15:50  v9fly  阅读(127)  评论(0编辑  收藏  举报