题面

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

二分答案,然后我们要把一圈分成三块,使这三块的大小都$\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=0; bool f=1; char c=getchar();
10     for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
11     for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
12     if(f) return x;
13     return 0-x;
14 }
15 int n,n1;
16 long long a[N<<1],sfx[N<<1];
17 long long judge(long long x){
18     //printf("x:%d\n",x);
19     int dir,dir2; long long mx=-1;
20     for(int i=1;sfx[i+n1-1]-sfx[i-1]>=x*3;++i){
21         dir=lower_bound(sfx+i,sfx+i+n1,x+sfx[i-1])-sfx;
22         if(sfx[dir]-sfx[i-1]>x) --dir;
23         if(dir<i) continue;
24         dir2=lower_bound(sfx+dir+1,sfx+i+n1,x+sfx[dir])-sfx;
25         if(dir2<=dir) dir2=dir+1;
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-1 && sfx[i+n1-1]-sfx[dir2]>=sfx[dir]-sfx[i-1]) mx=max(mx,sfx[dir]-sfx[i-1]);
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=1;i<=n;i++) a[i]=a[i+n]=read(), sfx[i]=sfx[i-1]+a[i];
38     n<<=1;
39     for(;i<=n;i++) sfx[i]=sfx[i-1]+a[i];
40     long long l=0,r=(sfx[n]+n-1)/3,mid,ret,ans=-1;
41     while(l<=r){
42         mid=(l+r)>>1;
43         ret=judge(mid);
44         if(ret!=-1) ans=ret, l=mid+1;
45         else r=mid-1;
46     }
47     printf("%lld\n",ans);
48     return 0;
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=0; bool f=1; char c=getchar();
10     for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
11     for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
12     if(f) return x;
13     return 0-x;
14 }
15 int n,n1;
16 long long a[N<<1],sfx[N<<1];
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-1])-sfx;
22     if(sfx[dir]-sfx[i-1]>x) --dir;
23     if(dir<i || dir>=i+n1-2) return -1;
24
25     dir2=lower_bound(sfx+dir+1,sfx+i+n1,(sfx[dir]<<1)-sfx[i-1])-sfx;
26     if(dir2>=i+n1-1) return -1;
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-1]-sfx[dir2]>=sfx[dir]-sfx[i-1]) return sfx[dir]-sfx[i-1];
30     return -1;
31 }
32 int main(){
33     n=n1=read();
34     int i;
35     for(i=1;i<=n;i++) a[i]=a[i+n]=read(), sfx[i]=sfx[i-1]+a[i];
36     n<<=1;
37     for(;i<=n;i++) sfx[i]=sfx[i-1]+a[i];
38     int dir,dir2;
39     long long ans=-1;
40     for(int i=1; i<=n1; i++){
41         long long l=1,r=sfx[n1]/3,mid,ret,res=-1;
42         while(l<=r){
43             mid=(l+r)>>1;
44             ret=judge(i,mid);
45             if(ret!=-1) res=ret, l=mid+1;
46             else r=mid-1;
47         }
48         ans=max(ans,res);
49     }
50     printf("%lld\n",ans);
51     return 0;
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=1000000+101010;
11 inline int read(){
12     int x=0,f=1;char ch=getchar();
13     for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
14     for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
15     return x*f;
16 }
17 ll n,a[maxn],sum,num[maxn];
18
19
20 bool erfe(ll l,ll r,ll he){
21     ll l1=l,r1=r,ans=0;
22     while(r1>=l1){
23         ll mid=r1+l1>>1;
24         ll qq=num[mid]-num[l-1],ww=num[n]-qq-he;
25         if(qq>=he){
26             if(ww>=he)return 1;
27             else r1=mid-1;
28         }
29         else l1=mid+1;
30     }
31     return 0;
32 }
33 ll aa;
34 ll erf(ll l,ll r){
35     ll l1=l,r1=r,ans=0;
36     while(r1>=l1){
37         ll mid=r1+l1>>1;
38         if(num[mid]-num[l-1]<=sum){
39             if(erfe(mid+1,r,num[mid]-num[l-1]))ans=max(ans,num[mid]-num[l-1]),l1=mid+1;
40             else r1=mid-1;
41         }
42         else r1=mid-1;
43     }
44     return ans;
45 }
46
47 ll ans=0;
48 void zj(){
49     for(ll i=1;i<=n;i++){
50         ans=max(ans,erf(i,n+i-1));
51     }
52     printf("%lld",ans);
53     return ;
54 }
55
56 int main(){
57     n=read();
58     for(ll i=1;i<=n;i++){
59         a[i]=read();
60         num[i]=num[i-1]+a[i];
61         sum+=a[i];
62     }
63     for(ll i=n+1;i<=2*n;i++)a[i]=a[i-n],num[i]=num[i-1]+a[i];
64     sum=sum/3;
65     zj();
66     return 0;
67 }

WZQ的做法

滑窗没写先凑乎吧。

转载于:https://www.cnblogs.com/scx2015noip-as-php/p/9734669.html

【2018.10.1】「JOI 2014 Final」年轮蛋糕相关推荐

  1. 「JOI 2016 Final」断层

    嘟嘟嘟 今天我们模拟考这题,出的是T3.实在是没想出来,就搞了个20分暴力(还WA了几发). 这题关键在于逆向思维,就是考虑最后的\(n\)的个点刚开始在哪儿,这样就减少了很多需要维护的东西. 这就让 ...

  2. Luogu P5103 「JOI 2016 Final」断层 树状数组or线段树+脑子

    太神仙了这题... 原来的地面上升,可以倒着操作(时光倒流),转化为地面沉降,最后的答案就是每个点的深度. 下面的1,2操作均定义为向下沉降(与原题意的变换相反): 首先这个题目只会操作前缀和后缀,并 ...

  3. T3:LOJ2332「JOI 2017 Final」焚风现象.cpp

    记录差值 然后每次运算一下头和尾 如果尾端是最后一次增加则不用运算尾端 详见代码 #include<iostream> #include<cstdio> #include< ...

  4. Libre OJ P2332「JOI 2017 Final」焚风现象【差分思想】By cellur925

    题目传送门 这道题开始看起来会很晕...\(qwq\).首先我们要明确题目中的海拔&&温度.温度是受海拔影响的,每次改变的是海拔,我们求的是温度. 我们开始读入的时候便可以处理出开始\ ...

  5. 【题解】LOJ3254:「JOI 2020 Final」集邮比赛 3

    原题传送门 发现 n < = 200 n<=200 n<=200,那么我们就可以想一个 O ( n 3 ) O(n^3) O(n3)的dp 发现每次肯定是向左/右推进 可以令 d p ...

  6. 「JOISC 2014 Day3」稻草人

    「JOISC 2014 Day3」稻草人 问题简述 解析 代码 问题简述 链接 https://loj.ac/problem/2880   给定 n n n个稻草人(横纵坐标是不大于 1 0 9 10 ...

  7. 「JOISC 2014 Day1」巴士走读

    「JOISC 2014 Day1」巴士走读 题解部分: (如果不怎么喜欢看推导的人可以直接看下面的关键部分,在段尾会有标注(或者看完定义直接看代码)) 本题让我们求到达点n需要最晚何时到达点1,我们可 ...

  8. 「JOISC 2014 Day4」挂饰(背包DP)题解

    题目翻译 JOI 君有 n n n 个装在手机上的挂饰,编号为 1 - n 1 \ldots n 1-n. JOI 君可以将其中一些挂饰装在手机上. JOI 君的挂饰有一些与众不同--其中的一些挂饰附 ...

  9. [JOI 2014 Final]裁剪线

    题目 传送门 to LOJ 思路 思路来自于官方题解,有兴趣的 日语高超的 可以自己找来看一看.这里就直接贴出翻译后的截图了 考虑一种并查集的做法,给每一个"区域"分配一个并查集编 ...

最新文章

  1. 【drp 12】再识转发和重定向:SpringMVC无法跳转页面
  2. C# 2.0 套接字编程实例初探
  3. Java实现Google第三方登录
  4. Maven学习-优化和重构POM
  5. 高效KMP字符匹配算法就这么简单
  6. P8U8 IT这块出书门槛相对比较低
  7. Kotlin学习笔记18 反射Part2
  8. java与sql心得体会_学习心得
  9. 2019最新k8s集群搭建教程 (centos k8s 搭建)
  10. 【安全狐】robots协议详解(robots.txt)
  11. jQuery 倒计时插件
  12. APK无法识别gsensor问题剖析
  13. 郑州轻工业大学oj平台 c语言 1008 美元和人民币的换算
  14. python分离arw与jpg图片
  15. Linux终端Terminal常用快捷键
  16. PHP开发环境配置指南
  17. 谁要GMAIL和Orkut的邀请?
  18. 出现这个错误的解决方法No enclosing instance of type 类名 is accessible. Must qualify the allocation with
  19. [转]为ERP的定义“拨乱反正”
  20. 准备搬家,送所有书籍!

热门文章

  1. 做一个简单的“远程”开关 ESP8266 + APP
  2. winform制作音乐播放器
  3. 不同直径的圆转一圈后,滚过的距离相同?谈一下亚里士多德车轮悖论与无穷小
  4. TIME_WAIT状态存在的意义
  5. 使用计算机需要准备硬件和什么,当个人计算机需要使用ADSL访问Internet时,所需的基本硬件设施是什么?...
  6. Springboot项目 logging level配置
  7. FPGA与CPLD之区别
  8. 两种电子配线架的原理比较
  9. Android之实现手机号码拦截
  10. [HITCON 2016]Leaking-nodejsVM沙箱逃逸