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
注意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;
}
静渊以有谋,疏通而知事。