题目链接:http://codeforces.com/contest/934/problem/C
题意:
给你n个数,只有数字1和2,你可以翻转任意一个区间,使得整个序列的最长递增子序列尽可能长
求出最长的最长递增子序列
思路:
先求出不翻的最大值,这个只要前缀1的个数s1[]和后缀2的个数s2[]相加取最大就行了
之后暴力枚举翻转的区间,对于区间[x, y]当前的最长递增子序列就为s1[x-1]+s2[y+1]+LIS[x, y]
其中所有的LIS可以用dp预处理(dp[x][y][p]表示从x到y最后一个数字为p的最长递增子序列)
复杂度O(n²)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[2005], bet[2005][2005], dp[2005][2], s1[2005], s2[2005];
int main(void)
{
int n, i, j, ans;
scanf("%d", &n);
for(i=1;i<=n;i++)
scanf("%d", &a[i]);
for(i=n;i>=1;i--)
{
bet[i][i] = 1;
memset(dp, 0, sizeof(dp));
if(a[i]==1)
dp[i][1] = dp[i][2] = 1;
else
dp[i][2] = 1;
for(j=i-1;j>=1;j--)
{
if(a[j]==1)
{
dp[j][1] = dp[j+1][1]+1;
dp[j][2] = max(dp[j+1][2], dp[j][1]);
}
else
{
dp[j][1] = dp[j+1][1];
dp[j][2] = max(dp[j+1][2]+1, dp[j][1]);
}
bet[j][i] = dp[j][2];
}
}
for(i=1;i<=n;i++)
{
s1[i] = s1[i-1];
if(a[i]==1)
s1[i]++;
}
for(i=n;i>=1;i--)
{
s2[i] = s2[i+1];
if(a[i]==2)
s2[i]++;
}
ans = 0;
for(i=1;i<=n-1;i++)
ans = max(ans, s1[i]+s2[i+1]);
for(i=1;i<=n;i++)
{
for(j=i;j<=n;j++)
{
ans = max(ans, s1[i-1]+s2[j+1]+bet[i][j]);
//printf("%d ", bet[i][j]);
}
//printf("\n");
}
printf("%d\n", ans);
return 0;
}