题解:P16350 「Gensokyo OI Round 1」隙间插曲
赛时想了好久,真难吧。不过感觉远小于 C(不会组合数学导致的)。
solution
考虑所有保留下来的值,它们是不能被删除的,下文把这些位置称为关键点。
令序列中有
考虑连续两个关键点间形成的区间,这个区间需要被删空,那么对于这个区间的每个后缀,令
原因是如果有一个后缀
对于最后一个关键点以后的区间同样需要满足每个后缀
可以发现所选的关键点集合满足以上条件就符合题意了,构造出来也不难,每个区间的
我们可以预处理出所有合法的区间,对于
令
用树状数组优化一下可以做到严格
实现时可以钦定
:::info[code]
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
const int N=1e3+10;
const int inf=1e9+10;
inline void read(int &x) {
x=0;
char ch=getchar();
while (ch<48) ch=getchar();
while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
int n,m;
int a[N],mn[N];
struct BIT {
ll v[N];
inline void add(int p,ll k) {for(;p<=n+2;p+=(p&-p))v[p]=max(v[p],k);}
inline ll qry(int p){ll r=0;for(;p;p-=(p&-p))r=max(r,v[p]);return r;}
}tr[N];
int main() {
read(n);
f(i,1,n) read(a[i]),m+=(!a[i]);m*=2;
f(i,1,n+1) {
int c0=0,c1=0;
F(j,i-1,1) {
if (c0<c1) break;
if (!a[j]) c0++;
else c1++;
mn[i]=j;
}
}
f(i,1,n+1) {
F(j,n-m+1,2) {
ll res=tr[j-1].qry(n-mn[i]+2)+a[i];
tr[j].add(n-i+2,res);
if (i==n+1&&j==n-m+1) printf("%lld\n",res);
}
tr[1].add(n-i+2,a[i]);
}
if (n==m) puts("0");
return 0;
}
:::