码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-08-09 17:21:25      阅读:89      评论:0      收藏:0      [点我收藏+]

标签:class   art   重复   oid   mem   \n   cond   tac   c++   

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

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

标签:class   art   重复   oid   mem   \n   cond   tac   c++   

原文地址:https://www.cnblogs.com/sbfhy/p/9449297.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!