题解:CF2018D Max Plus Min Plus Size
一道很妙的题。动态 DP。
首先,一个很显然的想法是令
考虑优化。显然这个状态数就有很大问题,所以我们必须减少状态数量。根据数学直觉,最优解里面一定有一个染色方案染红了至少一个全局最大值。我们取任意一个染色方案,其染红的数下标集合为
从而,我们可以钦定红数的
为了省事,我写的代码是
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int _=4e5+5,inf=1e9;
multiset<int>d;
int f[_][2][2][2],a[_],b[_],v[_],l[_],r[_],h[_],e[_],c,s,mx,w,n,T;
map<int,vector<int> >p;
int g(int x){
return b[x]==x?x:b[x]=g(b[x]);
}
inline void del(int x){
multiset<int>::iterator u=d.lower_bound(x);
if(u!=d.end()&&(*u)==x)d.erase(u);
}
inline void mer(int x,int y){
b[x]=b[y]=++c;l[c]=l[x];r[c]=r[y];
del(h[x]);del(h[y]);s-=e[x];s-=e[y];
h[c]=inf;e[c]=0;
for(int i:{0,1})
for(int j:{0,1})
for(int k:{0,1})
for(int I=0;I<2-k;I++)
for(int J:{0,1})
for(int K:{0,1})f[c][i][j][J|K]=max(f[c][i][j][J|K],f[x][i][k][J]+f[y][I][j][K]);
for(int i:{0,1})
for(int j:{0,1})e[c]=max(e[c],f[c][i][j][0]);
for(int i:{0,1})
for(int j:{0,1})h[c]=min(h[c],e[c]-f[c][i][j][1]);
d.insert(h[c]);s+=e[c];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;mx=w=s=0;c=n;p.clear();d.clear();
for(int i=1;i<=n;i++){
cin>>a[i];v[i]=0;
e[i]=1;l[i]=r[i]=i;
mx=max(mx,a[i]);
p[-a[i]].push_back(i);
}
for(int i=1;i<n+n;i++){
b[i]=i;
for(int j:{0,1})
for(int k:{0,1})
for(int I:{0,1})f[i][j][k][I]=-inf;
}
for(int i=1;i<=n;i++)
if(a[i]==mx){
h[i]=0;
for(int j:{0,1})f[i][j][j][j]=j;
f[i][1][1][0]=1;
}else{
h[i]=inf;
for(int j:{0,1})f[i][j][j][0]=j;
}
for(auto i:p){
for(int j:i.second){
d.insert(h[j]);s+=e[j];
if(j>1&&v[j-1])mer(g(j-1),g(j));
if(j<n&&v[j+1])mer(g(j),g(j+1));
v[j]=1;
}
w=max(w,mx-i.first+s-*d.begin());
}
cout<<w<<'\n';
}
return 0;
}