题目意思: 给长度为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\n",x)
#define pd(x) printf("%f\n",x)
#define pl(x) printf("%lld\n",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;
}
超强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\n", max(ma3, ma4));return 0;
}