【IOI2014】bzoj4367 holiday

来源:互联网 发布:windows只能进安全模式 编辑:程序博客网 时间:2024/05/17 21:07

最优方案一定是先向一边走,然后掉头回来,再向另一边走停在最远处,剩下的时间取走一路上的最大值。
我们用f[0/1][0/1][i]表示用掉时间i,向左或向右,回到出发点或不回到,得到的最大收益。不难发现,这四个值求法类似。
如果知道到达的最远点的话,能取走的位置的个数是确定的。我么可以用主席树查询区间k大值和来O(logn)求出答案。而显然决策点是单调的,也就是说,时间越长,走到的最远点越远。于是我们可以分治求解,定义solve(L,R,l,r)表示求解[L,R]f值,决策点在[l,r]。令mid=(L+R)/2,先暴力枚举决策点求出mid的最优决策x,这一步是O(nlogn)的,于是递归下去的时候决策点也分成了两部分。分治结构总共有O(logn)层,每一层求解的复杂度之和是O(nlogn),所以最后的复杂度是O(nlog2n)
注意起点位置是不能被两边同时取走的,因此需要特殊处理。好像只有规定往回走的那一边取走起点才是对的,我也不知道为什么。

#include<cstdio>#include<algorithm>using namespace std;const int maxn=100010,maxt=2800000;#define LL long longint rd(){    int x=0;    char c=getchar();    while (c<'0'||c>'9') c=getchar();    while (c>='0'&&c<='9')    {        x=x*10+c-'0';        c=getchar();    }    return x;}int a[maxn],val[maxn],size[maxt],lson[maxt],rson[maxt],rt[maxn],n,s,m,l,tot;LL sum[maxt],f[2][2][250010];void build(int &u,int bro,int L,int R,int x){    u=++tot;    size[u]=size[bro]+1;    sum[u]=sum[bro]+val[x];    if (L==R) return;    int mid=(L+R)/2;    if (x<=mid)    {        build(lson[u],lson[bro],L,mid,x);        rson[u]=rson[bro];    }    else    {        lson[u]=lson[bro];        build(rson[u],rson[bro],mid+1,R,x);    }}LL qry(int u,int v,int L,int R,int k){    if (k>=size[u]-size[v]) return sum[u]-sum[v];    if (L==R) return k*val[L];    int mid=(L+R)/2;    if (k<=size[rson[u]]-size[rson[v]]) return qry(rson[u],rson[v],mid+1,R,k);    return sum[rson[u]]-sum[rson[v]]+qry(lson[u],lson[v],L,mid,k-(size[rson[u]]-size[rson[v]]));}LL cal(int f1,int f2,int t,int p){    int u,v,x;    if (f1) u=s+f2,v=p;    else u=p,v=s-f2;    x=t-abs(p-s)*(f2?1:2);    if (x<=0||u>v) return 0;    return qry(rt[v],rt[u-1],1,l,x);}void solve(int f1,int f2,int L,int R,int l,int r){    if (L>R) return;    int mid=(L+R)/2,p=l;    LL x;    f[f1][f2][mid]=cal(f1,f2,mid,l);    for (int i=l+1;i<=r;i++)    {        x=cal(f1,f2,mid,i);        if (x>f[f1][f2][mid])        {            p=i;            f[f1][f2][mid]=x;        }    }    if (f1)    {        solve(f1,f2,L,mid-1,l,p);        solve(f1,f2,mid+1,R,p,r);    }    else    {        solve(f1,f2,L,mid-1,p,r);        solve(f1,f2,mid+1,R,l,p);    }}int main(){    //freopen("f.in","r",stdin);    //freopen("f.out","w",stdout);    LL ans=0;    n=rd();    s=rd()+1;    m=rd();    for (int i=1;i<=n;i++) a[i]=val[i]=rd();    sort(val+1,val+n+1);    l=unique(val+1,val+n+1)-val-1;    for (int i=1;i<=n;i++)    {        a[i]=lower_bound(val+1,val+l+1,a[i])-val;        build(rt[i],rt[i-1],1,l,a[i]);    }    solve(0,0,0,m,1,s);    solve(0,1,0,m,1,s);    solve(1,0,0,m,s,n);    solve(1,1,0,m,s,n);    for (int i=0;i<=m;i++)    {        ans=max(ans,f[0][0][i]+f[1][1][m-i]);        ans=max(ans,f[0][1][i]+f[1][0][m-i]);    }    printf("%lld\n",ans);}
原创粉丝点击