zoukankan      html  css  js  c++  java
  • 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
    ", ans, ansl, ansr);
        }
    
        return 0;
    }
    
  • 相关阅读:
    关于程序收到消息的顺序
    窗口过程
    消息循环
    解剖窗口程序
    开始了解窗口程序
    编码的规范
    汇编的除法和乘法
    Win32汇编--Win32汇编的高级语法
    H5-音频列表音乐切换
    移动端-ibokan
  • 原文地址:https://www.cnblogs.com/sbfhy/p/9449297.html
Copyright © 2011-2022 走看看