#C231116D. 最长不下降子序列(lis)
前言(Front talk)
网址(Website)
题目(Problem)
大意:给出
- 区间翻转,翻转任意区间(
); - 输出翻转后能达到的最长不下降子序列长度;
注意:
- 输入: 第一行一个整数
,表示 串的段数。 接下来 行每行两个整数 , 。 表示第 段是全 还是全 , 表示第 段的长度。保证 。第 行一个整数 。 - 输出:共有
行,输出翻转后能达到的最长不下降子序列长度,==其中第一行为原 串的 长度==,后面 行表示每次操作。
范围:
题解(Solution)
对于一个
考虑转化:先计算出所有的
那么我们再来考虑每次翻转,很明显,如果当前的翻转取得了一个最优的
- 找到一个不在当前的
计算的区间里面的 ,将这个区间放在要计入的 里面,一定有正贡献; - 替换一部分区间出来(要不然
的值不会被影响),这个区间不好寻找,但是我们知道,在该区间被替换出去以后, 就变成了 ,其中 代表有最大正贡献的区间, 代表要被替换掉的区间。而当前的最大贡献区间已经求出来了,我们就只需要找到前面的最大的 就可以了。
对于每一次操作,倒着处理一遍,可以在
代码(Code)
70pts
#include<bits/stdc++.h>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define int long long
inline int input(){int x;return cin>>x,x;}
const int N = 201234;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n,m,a[N],sum[N],res;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
freopen("lis.in","r",stdin);
freopen("lis.out","w",stdout);
n=input();For(i,1,n){
int x=input(),y=input();if(x) a[i]=-y,res+=y;
else a[i]=y;
}m=input();
for(int i=1;i<=m+1;++i){
int mx=0;for(int j=1;j<=n;j++) sum[j]=sum[j-1]+a[j],mx=max(mx,sum[j]);
cout<<mx+res<<'\n';if(i==m+1) break;
int l=1,r=1;
int sy=-inf,y=0,sz=-inf,z=0;
for(int j=n;j>=1;j--){
if(sum[j]>sz) sz=sum[j],z=j;
if(sz-sum[j-1]>sy) sy=sz-sum[j-1],y=z;
if(sy+sum[j-1]>mx) mx=sy+sum[j-1],l=j,r=y;
}reverse(a+l,a+r+1);
}return 0;
}
100pts