zoukankan      html  css  js  c++  java
  • Codeforces Round #462 (Div. 2), problem: (C) A Twisty Movement (求可以转一次区间的不递增子序列元素只有1,2)

    题目意思: 给长度为n(n<=2000)的数字串,数字只能为1或者2,可以将其中一段区间[l,r]翻转,求翻转后的最长非递减子序列长度。

    题解:求出1的前缀和,2的后缀和,以及区间[i,j]的最长不递增子序列。

    f[i][j][0]表示区间i-j以1结尾的最长不递增子序列;

    f[i][j][1]表示区间i-j以2结尾的最长不递增子序列,显然是区间i-j 2的个数;

    所以转移方程为:

       f[i][j][1] = f[i][j-1][1] + (a[j]==2);
       f[i][j][0] = max(f[i][j-1][0], f[i][j-1][1]) + (a[j]==1);(1<=i<=n,i<=j<=n)

    //#include"bits/stdc++.h"
    #include <sstream>
    #include <iomanip>
    #include"cstdio"
    #include"map"
    #include"set"
    #include"cmath"
    #include"queue"
    #include"vector"
    #include"string"
    #include"cstring"
    #include"time.h"
    #include"iostream"
    #include"stdlib.h"
    #include"algorithm"
    #define db double
    #define ll long long
    #define vec vector<ll>
    #define mt  vector<vec>
    #define ci(x) scanf("%d",&x)
    #define cd(x) scanf("%lf",&x)
    #define cl(x) scanf("%lld",&x)
    #define pi(x) printf("%d
    ",x)
    #define pd(x) printf("%f
    ",x)
    #define pl(x) printf("%lld
    ",x)
    //#define rep(i, x, y) for(int i=x;i<=y;i++)
    #define rep(i,n) for(int i=0;i<n;i++)
    const int N   = 2e3 + 5;
    const int mod = 1e9 + 7;
    const int MOD = mod - 1;
    const int inf = 0x3f3f3f3f;
    const db  PI  = acos(-1.0);
    const db  eps = 1e-10;
    using namespace std;
    int a[N];
    int l[N],r[N];
    int f[N][N][2];
    int main()
    {
        int n;
        ci(n);
        for(int i=1;i<=n;i++) ci(a[i]),l[i]=l[i-1]+(a[i]==1);
        for(int i=n;i>=0;i--) r[i]=r[i+1]+(a[i]==2);
        int ma=-1;
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                f[i][j][1]=f[i][j-1][1]+(a[j]==2);
                f[i][j][0]=max(f[i][j-1][0],f[i][j-1][1])+(a[j]==1);
                ma=max(ma,f[i][j][1]+l[i-1]+r[j+1]);
                ma=max(ma,f[i][j][0]+l[i-1]+r[j+1]);
            }
        }
        pi(ma);
        return 0;
    }
    View Code

    超强O(n) 解法

    翻转后的合法子序列翻转前一定是 一坨1 + 一坨2 + 一坨1 + 一坨2形式,坨可以为空,于是可以用4个变量分别维护前1坨,前2坨,前3坨,前4坨的最大值,更新时每个变量也只用上一轮最多两个变量更新,比如当前元素为2,那么前两坨的最大值ma2 = max(ma1, ma2) + 1,ma4 = max(ma3, ma4) + 1。因为将2接到ma1或ma2后的序列都是合法的ma2形式。代码十分简短。时间复杂度O(n),空间复杂度O(1)。

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <set>
    #include <map>
    #include <list>
    #include <iomanip>
    #include <cctype>
    #include <cassert>
    #include <bitset>
    #include <ctime>
    
    using namespace std;
    
    #define pau system("pause")
    #define ll long long
    #define pii pair<int, int>
    #define pb push_back
    #define mp make_pair
    #define clr(a, x) memset(a, x, sizeof(a))
    
    const double pi = acos(-1.0);
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    const double EPS = 1e-9;
    
    int ma1, ma2, ma3, ma4, x, n;
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &x);
            if (1 == x) {
                ++ma1;
                ma3 = max(ma3, ma2) + 1;
            } else {
                ma2 = max(ma1, ma2) + 1;
                ma4 = max(ma4, ma3) + 1;
            }
        }
        printf("%d
    ", max(ma3, ma4));
        return 0;
    }
    View Code
  • 相关阅读:
    nodejs + typescirpt + vs code
    NodeJs使用nodejs-websocket + protobuf
    Windows10环境下使用VisualSVN server搭建SVN服务器
    微信小游戏下socket.io的使用
    JS中实现种子随机数
    帧同步和状态同步
    EgretPaper学习笔记一 (安装环境,新建项目)
    反编译微信小游戏
    微信小游戏 小程序跳转修改 不支持动态更新,只能在发布时修改
    HTML5实现本地JSON文件的读写
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10345628.html
Copyright © 2011-2022 走看看