IOI2014 Holiday

Holiday

健佳正在制定下个假期去台湾的游玩计划。在这个假期,健佳将会在城市之间奔波,并且参观这些城市的景点。

在台湾共有 \(n\) 个城市,它们全部位于一条高速公路上。这些城市连续地编号为 \(0\)\(n - 1\)。对于城市 \(i\) (\(0 < i < n - 1\)) 而言,与其相邻的城市是 \(i - 1\)\(i + 1\)。但是对于城市 \(0\),唯一与其相邻的是城市 \(1\)。而对于城市 \(n - 1\),唯一与其相邻的是城市 \(n - 2\)

每个城市都有若干景点。健佳有 \(d\) 天假期并且打算要参观尽量多的景点。健佳已经选择了假期开始要到访的第一个城市。在假期的每一天,健佳可以选择去一个相邻的城市,或者参观所在城市的所有景点,但是不能同时进行。即使健佳在同一个城市停留多次,他也不会去重复参观该城市的景点。请帮助健佳策划这个假期,以便能让他参观尽可能多的景点。

\(2 \leq n \leq 100000\)

题解

https://blog.csdn.net/CreationAugust/article/details/50821931

1

2

注意f,g计算的时候必须钦定一个能取到起点,一个不能取到起点。不然会算重。

CO int N=1e5+10;
int a[N];vector<int> b;
int root[N],tot;
int lc[N*18],rc[N*18],siz[N*18];
int64 sum[N*18];

#define mid ((l+r)>>1)
void insert(int&x,int l,int r,int p){
    ++tot;
    lc[tot]=lc[x],rc[tot]=rc[x],siz[tot]=siz[x]+1;
    sum[tot]=sum[x]+b[p-1];
    x=tot;
    if(l==r) return;
    if(p<=mid) insert(lc[x],l,mid,p);
    else insert(rc[x],mid+1,r,p);
}
int64 query(int x,int y,int l,int r,int k){
    if(k<=0) return 0;
    if(l==r) return (int64)min(k,siz[x]-siz[y])*b[l-1];
    int s=siz[rc[x]]-siz[rc[y]];
    if(s>=k) return query(rc[x],rc[y],mid+1,r,k);
    else return sum[rc[x]]-sum[rc[y]]+query(lc[x],lc[y],l,mid,k-s);
}
#undef mid

int S;
int64 f[3*N],g[3*N],f1[3*N],g1[3*N];

void solve_f(int l,int r,int L,int R){
    if(l>r) return;
    int mid=(l+r)>>1,pos=0;
    for(int i=L;i<=R;++i){
        int64 res=query(root[i],root[S-1],1,b.size(),mid-(i-S)); // count a[S]
        if(!pos or res>f[mid]) f[mid]=res,pos=i;
    }
    solve_f(l,mid-1,L,pos),solve_f(mid+1,r,pos,R);
}
void solve_g(int l,int r,int L,int R){
    if(l>r) return;
    int mid=(l+r)>>1,pos=0;
    for(int i=R;i>=L;--i){
        int64 res=query(root[S-1],root[i-1],1,b.size(),mid-(S-i)); // doesn't count a[S]
        if(!pos or res>g[mid]) g[mid]=res,pos=i;
    }
    solve_g(l,mid-1,pos,R),solve_g(mid+1,r,L,pos);
}
void solve_f1(int l,int r,int L,int R){
    if(l>r) return;
    int mid=(l+r)>>1,pos=0;
    for(int i=L;i<=R;++i){
        int64 res=query(root[i],root[S-1],1,b.size(),mid-2*(i-S));
        if(!pos or res>f1[mid]) f1[mid]=res,pos=i;
    }
    solve_f1(l,mid-1,L,pos),solve_f1(mid+1,r,pos,R);
}
void solve_g1(int l,int r,int L,int R){
    if(l>r) return;
    int mid=(l+r)>>1,pos=0;
    for(int i=R;i>=L;--i){
        int64 res=query(root[S-1],root[i-1],1,b.size(),mid-2*(S-i));
        if(!pos or res>g1[mid]) g1[mid]=res,pos=i;
    }
    solve_g1(l,mid-1,pos,R),solve_g1(mid+1,r,L,pos);
}

int main(){
    int n=read<int>();
    S=read<int>()+1;
    int m=read<int>();
    for(int i=1;i<=n;++i) b.push_back(read(a[i]));
    sort(b.begin(),b.end());
    b.erase(unique(b.begin(),b.end()),b.end());
    for(int i=1;i<=n;++i){
        a[i]=lower_bound(b.begin(),b.end(),a[i])-b.begin()+1;
        insert(root[i]=root[i-1],1,b.size(),a[i]);
    }
    solve_f(1,m,S,min(S+m,n));
    solve_g(1,m,max(S-m,1),S);
    solve_f1(1,m,S,min(S+m/2,n));
    solve_g1(1,m,max(S-m/2,1),S);
    int64 ans=0;
    for(int i=0;i<=m;++i) ans=max(ans,max(g1[i]+f[m-i],f1[i]+g[m-i]));
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12302451.html