[BZOJ4367][IOI2014]Holiday(决策单调性+分治+主席树)
4367: [IOI2014]holiday假期
Time Limit: 20 Sec Memory Limit: 64 MB
Submit: 421 Solved: 128
[Submit][Status][Discuss]Description
健佳正在制定下个假期去台湾的游玩计划。在这个假期,健佳将会在城市之间奔波,并且参观这些城市的景点。
在台湾共有n个城市,它们全部位于一条高速公路上。这些城市连续地编号为0到n-1。对于城市i(0<i<n-1)而言,与其相邻的城市是i-1和i+1。但是对于城市 0,唯一与其相邻的是城市 1。而对于城市n-1,唯一与其相邻的是城市n-2。
每个城市都有若干景点。健佳有d天假期并且打算要参观尽量多的景点。健佳已经选择了假期开始要到访的第一个城市。在假期的每一天,健佳可以选择去一个相邻 的城市,或者参观所在城市的所有景点,但是不能同时进行。即使健佳在同一个城市停留多次,他也不会去重复参观该城市的景点。请帮助健佳策划这个假期,以便 能让他参观尽可能多的景点。Input
第1行: n, start, d.
第2行: attraction[0], ..., attraction[n-1].
n: 城市数。
start: 起点城市的编号。
d: 假期的天数。
attraction: 长度为n的数组;attraction[i] 表示城市i的景点数目,其中0≤i≤n-1。Output
输出一个整数表示健佳最多可以参观的景点数。
Sample Input
5 2 7
10 2 20 30 1Sample Output
60HINT
假 设健佳有 7 天假期,有 5 个城市(参见下表),而且他由城市 2 开始。在第一天,健佳参观城市2的 20 个景点。第二天,健佳由城市 2 去往城市 3。而在第三天,健佳参观城市 3 的30 个景点。接下来的3天,健佳由城市 3 前往城市 0。而在第 7 天,健佳参观城市0的 10 个景点。这样健佳参观的景点总数是20+30+10=60,这是他由城市 2 开始、在 7 天假期内最多能参观的景点数目。
Source
[Submit][Status][Discuss]
https://blog.csdn.net/CreationAugust/article/details/50821931
当需要枚举的东西呈单调性的时候可以用分治解决。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=l; i<=r; i++) 5 typedef long long ll; 6 using namespace std; 7 8 const int N=250010,M=1800010; 9 int n,st,m,cnt,root[N],b[N],sta[N],c,ls[M],rs[M],sz[M]; 10 ll ret,ans,sum[M],f[N],g[N],f1[N],g1[N]; 11 int fd[N],gd[N],f1d[N],g1d[N]; 12 13 void ins(int x,int &y,int l,int r,int val,ll Val){ 14 sz[y=++cnt]=sz[x]+1; sum[y]=sum[x]+Val; ls[y]=ls[x];rs[y]=rs[x]; 15 if (l==r) return; int mid=(l+r)>>1; 16 if (val<=mid) ins(ls[x],ls[y],l,mid,val,Val); 17 else ins(rs[x],rs[y],mid+1,r,val,Val); 18 } 19 20 void query(int x,int y,int l,int r,int k){ 21 if (k<=0) return; 22 if (l==r) { ret+=1ll*min(k,sz[y]-sz[x])*sta[l]; return; } 23 int mid=(l+r)>>1; 24 if (sz[rs[y]]-sz[rs[x]]>=k) query(rs[x],rs[y],mid+1,r,k); 25 else ret+=sum[rs[y]]-sum[rs[x]],query(ls[x],ls[y],l,mid,k-sz[rs[y]]+sz[rs[x]]); 26 } 27 28 void solve1(int l,int r,int L,int R){//要求f[l..r],d的范围在[L,R] 29 if (l>r) return; 30 int mid=(l+r)>>1; 31 for (int i=L;i<=R;i++){ 32 ret=0; query(root[st-1],root[i],1,c,st-i+mid); 33 if (ret>f[mid]||!fd[mid]) f[mid]=ret,fd[mid]=i; 34 } 35 solve1(l,mid-1,L,fd[mid]);solve1(mid+1,r,fd[mid],R); 36 } 37 38 void solve2(int l,int r,int L,int R){ 39 if (l>r) return; 40 int mid=(l+r)>>1; 41 for (int i=R; i>=L; i--){ 42 ret=0; query(root[i-1],root[st-1],1,c,i-st+mid); 43 if (ret>g[mid]||!gd[mid]) g[mid]=ret,gd[mid]=i; 44 } 45 solve2(l,mid-1,gd[mid],R); solve2(mid+1,r,L,gd[mid]); 46 } 47 48 void solve3(int l,int r,int L,int R){ 49 if (l>r) return; 50 int mid=(l+r)>>1; 51 for (int i=L; i<=R; i++){ 52 ret=0; query(root[st-1],root[i],1,c,((st-i)<<1)+mid); 53 if (ret>f1[mid]||!f1d[mid]) f1[mid]=ret,f1d[mid]=i; 54 } 55 solve3(l,mid-1,L,f1d[mid]); solve3(mid+1,r,f1d[mid],R); 56 } 57 58 void solve4(int l,int r,int L,int R){ 59 if (l>r) return; 60 int mid=(l+r)>>1; 61 for (int i=R;i>=L;i--){ 62 ret=0; query(root[i-1],root[st-1],1,c,((i-st)<<1)+mid); 63 if (ret>g1[mid]||!g1d[mid]) g1[mid]=ret,g1d[mid]=i; 64 } 65 solve4(l,mid-1,g1d[mid],R);solve4(mid+1,r,L,g1d[mid]); 66 } 67 68 int main(){ 69 freopen("bzoj4367.in","r",stdin); 70 freopen("bzoj4367.out","w",stdout); 71 scanf("%d%d%d",&n,&st,&m);st++; 72 rep(i,1,n) scanf("%d",&b[i]),sta[i]=b[i]; 73 sort(sta+1,sta+n+1);c=unique(sta+1,sta+n+1)-sta-1; 74 rep(i,1,n) b[i]=lower_bound(sta+1,sta+c+1,b[i])-sta; 75 rep(i,1,n) ins(root[i-1],root[i],1,c,b[i],sta[b[i]]); 76 solve1(1,m,st,min(n,st+m)); solve2(1,m,max(1,st-m),n); 77 solve3(1,m,st,min(n,st+(m>>1))); solve4(1,m,max(1,st-(m>>1)),n); 78 rep(i,0,m) ans=max(ans,g1[i]+f[m-i]); 79 rep(i,0,m) ans=max(ans,f1[i]+g[m-i]); 80 printf("%lld\n",ans); 81 }