题解:dp+数学证明
先分析一下这个单调子序列的性质。一定存在一个最优子序列,他的单调区间的长度不超过2.
假设最优子序列有m个单调区间,序列的数字总数为s,那么最大艺术价值为s/m
设最后一个区间的数字总数为t,那么s/m的范围一定是在s-t/m-1,t之间的。为什么呢?因为是区间求平均值,所以我们只保留两个值中较大的即可。那么我们总能找出区间个数为1或2的合法最优子序列。
那么选出来的子序列就有两种可能。
一种是一个单增序列,直接求值最大的单调序列就可以了;
另一种是单增序列+单减序列,正反求然后接起来。
然后用线段树优化一下。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 100003
using namespace std;
int n,m,c[N],pos[N],cnt;
double g[N],f[N],a[N],ans,tr[N*4];
int cmp(int x,int y)
{
return a[x]<a[y];
}
void update(int now)
{
tr[now]=max(tr[now<<1],tr[now<<1|1]);
}
void change(int now,int l,int r,int x,double v)
{
if (l==r) {
tr[now]=max(tr[now],v);
return;
}
int mid=(l+r)/2;
if (x<=mid) change(now<<1,l,mid,x,v);
else change(now<<1|1,mid+1,r,x,v);
update(now);
}
double qjask(int now,int l,int r,int ll,int rr)
{
if (ll>rr) return 0;
if (ll<=l&&r<=rr) return tr[now];
int mid=(l+r)/2;
double ans=0;
if (ll<=mid) ans=max(ans,qjask(now<<1,l,mid,ll,rr));
if (rr>mid) ans=max(ans,qjask(now<<1|1,mid+1,r,ll,rr));
return ans;
}
int main()
{
freopen("seq.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lf",&a[i]),c[i]=i;
sort(c+1,c+n+1,cmp);
pos[c[1]]=++cnt;
for (int i=2;i<=n;i++)
if (a[c[i]]!=a[c[i-1]]) pos[c[i]]=++cnt;
else pos[c[i]]=cnt;
f[1]=a[1]; change(1,1,cnt,pos[1],f[1]);
g[n]=a[n];
for (int i=2;i<=n;i++)
{
f[i]=qjask(1,1,cnt,1,pos[i]-1)+a[i];
change(1,1,cnt,pos[i],f[i]);
}
memset(tr,0,sizeof(tr));
change(1,1,cnt,pos[n],g[n]);
for (int i=n-1;i>=1;i--)
{
g[i]=qjask(1,1,cnt,1,pos[i]-1)+a[i];
change(1,1,cnt,pos[i],g[i]);
}
for (int i=1;i<=n;i++)
{
ans=max(ans,(g[i]+f[i]-a[i])/2);
ans=max(ans,f[i]);
}
printf("%.3lf",ans);
}