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
原文地址:https://www.cnblogs.com/shuaihui520/p/10345628.html