题面

一看到求“最小值的最大值”这种问题,就能想到二分了。

二分答案,然后我们要把一圈分成三块,使这三块的大小都$\geq mid$。做法是把环展开成2倍长度的链,先钦定一个起点,然后根据前缀和再二分一下前两块的最小大小(注意前两块要连着),第三块用一圈的大小减去前两块的大小即可得到。如果第三块的大小$\geq mid$就返回$true$,提高答案范围;否则返回$false$,降低答案范围。

这样就能卡着最优情况下最小那一块的最大值从而得出答案了。

上面这种做法是$O(n*log_n*log_a)$,且二分次数多,常数较大,比较卡时。能不能不二分前两块的最小大小而快速求出?

如果做过“不超过某数的最大区间和(所有数非负)”这种单调性显然的题的话应该知道,钦定起点、确定大小这样一个做法在单调意义下可以滑动窗口。在这里前两块其实也是滑窗,因此省掉了内层的二分。时间复杂度$O(n*log_a)$。

当然,把枚举起点的循环放到二分外边会快一点。

也可以改变枚举量(WZQ的做法),就是把二分最小大小 改为 二分前两块的长度,提高答案范围当且仅当第一块的大小$\leq mid$,第二、三块的大小$\geq mid$。这样时间复杂度大概为$O(n*log_n*log_n)$。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std;
  7. #define N 100002
  8. inline int read(){
  9. int x=; bool f=; char c=getchar();
  10. for(;!isdigit(c);c=getchar()) if(c=='-') f=;
  11. for(; isdigit(c);c=getchar()) x=(x<<)+(x<<)+(c^'');
  12. if(f) return x;
  13. return -x;
  14. }
  15. int n,n1;
  16. long long a[N<<],sfx[N<<];
  17. long long judge(long long x){
  18. //printf("x:%d\n",x);
  19. int dir,dir2; long long mx=-;
  20. for(int i=;sfx[i+n1-]-sfx[i-]>=x*;++i){
  21. dir=lower_bound(sfx+i,sfx+i+n1,x+sfx[i-])-sfx;
  22. if(sfx[dir]-sfx[i-]>x) --dir;
  23. if(dir<i) continue;
  24. dir2=lower_bound(sfx+dir+,sfx+i+n1,x+sfx[dir])-sfx;
  25. if(dir2<=dir) dir2=dir+;
  26. //printf("%d %d %lld %lld %lld\n",dir,dir2,sfx[dir]-sfx[i-1],sfx[dir2]-sfx[dir],sfx[i+n1-1]-sfx[dir2]);
  27. //cout<<(dir2<i+n1-1)<<' '<<(sfx[i+n1-1]-sfx[dir2]>=sfx[dir]-sfx[i-1])<<'\n';
  28. if(dir2<i+n1- && sfx[i+n1-]-sfx[dir2]>=sfx[dir]-sfx[i-]) mx=max(mx,sfx[dir]-sfx[i-]);
  29. }
  30. //printf("MX:%lld\n",mx);
  31. return mx;
  32. }
  33.  
  34. int main(){
  35. n=n1=read();
  36. int i;
  37. for(i=;i<=n;i++) a[i]=a[i+n]=read(), sfx[i]=sfx[i-]+a[i];
  38. n<<=;
  39. for(;i<=n;i++) sfx[i]=sfx[i-]+a[i];
  40. long long l=,r=(sfx[n]+n-)/,mid,ret,ans=-;
  41. while(l<=r){
  42. mid=(l+r)>>;
  43. ret=judge(mid);
  44. if(ret!=-) ans=ret, l=mid+;
  45. else r=mid-;
  46. }
  47. printf("%lld\n",ans);
  48. return ;
  49. }

最外层二分答案(较慢)

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std;
  7. #define N 100002
  8. inline int read(){
  9. int x=; bool f=; char c=getchar();
  10. for(;!isdigit(c);c=getchar()) if(c=='-') f=;
  11. for(; isdigit(c);c=getchar()) x=(x<<)+(x<<)+(c^'');
  12. if(f) return x;
  13. return -x;
  14. }
  15. int n,n1;
  16. long long a[N<<],sfx[N<<];
  17.  
  18. long long judge(int i,long long x){
  19. //printf("faq:%d %lld\n",i,x);
  20. int dir,dir2;
  21. dir=lower_bound(sfx+i,sfx+i+n1,x+sfx[i-])-sfx;
  22. if(sfx[dir]-sfx[i-]>x) --dir;
  23. if(dir<i || dir>=i+n1-) return -;
  24.  
  25. dir2=lower_bound(sfx+dir+,sfx+i+n1,(sfx[dir]<<)-sfx[i-])-sfx;
  26. if(dir2>=i+n1-) return -;
  27.  
  28. //printf("%d %d %lld %lld %lld\n",dir,dir2,sfx[dir]-sfx[i-1],sfx[dir2]-sfx[dir],sfx[i+n1-1]-sfx[dir2]);
  29. if(sfx[i+n1-]-sfx[dir2]>=sfx[dir]-sfx[i-]) return sfx[dir]-sfx[i-];
  30. return -;
  31. }
  32. int main(){
  33. n=n1=read();
  34. int i;
  35. for(i=;i<=n;i++) a[i]=a[i+n]=read(), sfx[i]=sfx[i-]+a[i];
  36. n<<=;
  37. for(;i<=n;i++) sfx[i]=sfx[i-]+a[i];
  38. int dir,dir2;
  39. long long ans=-;
  40. for(int i=; i<=n1; i++){
  41. long long l=,r=sfx[n1]/,mid,ret,res=-;
  42. while(l<=r){
  43. mid=(l+r)>>;
  44. ret=judge(i,mid);
  45. if(ret!=-) res=ret, l=mid+;
  46. else r=mid-;
  47. }
  48. ans=max(ans,res);
  49. }
  50. printf("%lld\n",ans);
  51. return ;
  52. }

最外层枚举起点(快一点)

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<queue>
  8. #define ll long long
  9. using namespace std;
  10. const int maxn=+;
  11. inline int read(){
  12. int x=,f=;char ch=getchar();
  13. for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
  14. for(;isdigit(ch);ch=getchar())x=(x<<)+(x<<)+ch-'';
  15. return x*f;
  16. }
  17. ll n,a[maxn],sum,num[maxn];
  18.  
  19. bool erfe(ll l,ll r,ll he){
  20. ll l1=l,r1=r,ans=;
  21. while(r1>=l1){
  22. ll mid=r1+l1>>;
  23. ll qq=num[mid]-num[l-],ww=num[n]-qq-he;
  24. if(qq>=he){
  25. if(ww>=he)return ;
  26. else r1=mid-;
  27. }
  28. else l1=mid+;
  29. }
  30. return ;
  31. }
  32. ll aa;
  33. ll erf(ll l,ll r){
  34. ll l1=l,r1=r,ans=;
  35. while(r1>=l1){
  36. ll mid=r1+l1>>;
  37. if(num[mid]-num[l-]<=sum){
  38. if(erfe(mid+,r,num[mid]-num[l-]))ans=max(ans,num[mid]-num[l-]),l1=mid+;
  39. else r1=mid-;
  40. }
  41. else r1=mid-;
  42. }
  43. return ans;
  44. }
  45.  
  46. ll ans=;
  47. void zj(){
  48. for(ll i=;i<=n;i++){
  49. ans=max(ans,erf(i,n+i-));
  50. }
  51. printf("%lld",ans);
  52. return ;
  53. }
  54.  
  55. int main(){
  56. n=read();
  57. for(ll i=;i<=n;i++){
  58. a[i]=read();
  59. num[i]=num[i-]+a[i];
  60. sum+=a[i];
  61. }
  62. for(ll i=n+;i<=*n;i++)a[i]=a[i-n],num[i]=num[i-]+a[i];
  63. sum=sum/;
  64. zj();
  65. return ;
  66. }

WZQ的做法

滑窗没写先凑乎吧。

【2018.10.1】「JOI 2014 Final」年轮蛋糕的更多相关文章

  1. 【题解】LOJ2759. 「JOI 2014 Final」飞天鼠(最短路)

    [题解]LOJ2759. 「JOI 2014 Final」飞天鼠(最短路) 考虑最终答案的构成,一定是由很多飞行+一些上升+一些下降构成. 由于在任何一个点上升或者下降代价是一样的,所以: 对于上升操 ...

  2. 「JOI 2014 Final」飞天鼠

    「JOI 2014 Final」飞天鼠 显然向上爬是没有必要的,除非会下降到地面以下,才提高到刚好为0. 到达一个点有两种情况:到达高度为0和不为0. 对于高度不为0的情况,显然花费的时间越少高度越高 ...

  3. loj 2759「JOI 2014 Final」飞天鼠

    loj 这题有在一棵树上上升或者下降的操作,稍加分析后可以发现上升操作如果不是一定要做(指高度不足以到下一棵树或者是最后到达\(n\))就不做,下降操作也是如果不是一定要做(指到达下一棵树时高度过高) ...

  4. 「JOI 2014 Final」裁剪线

    做法一 首先将边界也视作四条裁剪线,整个平面作为一张纸,视存在 \(y = -\infty, y = +\infty, x = -\infty, x = +\infty\) 四条直线. 按照纵坐标依次 ...

  5. 「JOI 2017 Final」JOIOI 王国

    「JOI 2017 Final」JOIOI 王国 题目描述 题目译自 JOI 2017 Final T3「 JOIOI 王国 / The Kingdom of JOIOI」 JOIOI 王国是一个 H ...

  6. 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)

    LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...

  7. 「JOI 2015 Final」分蛋糕 2

    「JOI 2015 Final」分蛋糕 2 题解 这道题让我想起了新年趣事之红包这道DP题,这道题和那道题推出来之后的做法是一样的. 我们可以定义dp[i][len][1] 表示从第i块逆时针数len ...

  8. 「JOI 2015 Final」城墙

    「JOI 2015 Final」城墙 复杂度默认\(m=n\) 暴力 对于点\((i,j)\),记录\(ld[i][j]=min(向下延伸的长度,向右延伸的长度)\),\(rd[i][j]=min(向 ...

  9. 「JOI 2015 Final」舞会

    「JOI 2015 Final」舞会 略微思考一下即可知该过程可以化为一棵树.(3个贵族中选择1个,即新建一个节点连向这3个贵族). 该树的结点个数为\(2n\). 考虑二分答案mid. 判定的是公主 ...

随机推荐

  1. lua_to_luac

    #!/bin/sh `rm -rf allLua.zip` `mkdir ./tempScripts` `mkdir ./tempScripts/scripts` `cp -a ./scripts/ ...

  2. 【GIMP学习】抠图方法二则

    之前抠图都比较二,懒人我尝试过在线抠图软件.以及在线PS简易版,真的都很不好用,前者简单粗暴,后者我遇到各种储存不能的bug. 在ubuntu的环境下有一个功能可以和PS相媲美的功能强大图片处理软件G ...

  3. Synchronized关键字整理

    Synchronized关键字整理 作用:能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全效果. 两个用法: 1.对象锁: 包括方法锁(默认锁对象为this当前实例对象)和同步代码块 ...

  4. Open Cascade:AIS_InteractiveContext如何调用函数选择AIS对象

    AIS_InteractiveContext如何调用函数选择AIS对象 myAISContext->MoveTo(point.x, point.y, myView); myAISContext- ...

  5. hrbust-1545-基础数据结构——顺序表(2)

    http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1545 基础数据结构——顺序表(2) ...

  6. layuiadmin更新echarts

    发现layuiadmin中echarts版本有些老了,对其中的echarts进行了更新: 查询当前echarts版本: console.log(echarts.version); 1.前往echart ...

  7. Spring框架bean的注解管理方法之一 使用注解生成对象

    首先在原有的jar包: 需Spring压缩包中的四个核心JAR包 beans .context.core 和expression 下载地址: https://pan.baidu.com/s/1qXLH ...

  8. iOS旋屏

    横竖屏切换,视图乱了怎么办? 首先,我们必须了解一下下列4种状态,它们被用来描述设备旋转方向: UIInterfaceOrientationLandscapeLeft 向左,即HOME键在右 UIIn ...

  9. ios retain copy 以及copy协议

    阅读本文之前首先了解Copy与Retain的区别: Copy是创建一个新对象,Retain是创建一个指针,引用对象计数加1. Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的 ...

  10. mac拷贝原版和权限修复的命令行工具

    建议直接从安装盘中用命令复制,因为上传的kext权限会变,导致签名失败. 假定安装盘盘符是install_osx: sudo cp -R /Volumes/install_osx/S*/L*/E*/A ...