P1894セチの祈り

描述

在 Ninian 的花园里,有许多琼花,环绕着中间的凉亭。
有 N 片琼花,组成一个环。
Ninian 想在凉亭中发动 [セチの祈り] , 需要划分出三个区域的琼花,为了平均,要最大化面积最小的区域的面积。

划分区域:即用三刀把这个环分成三段,每段称之为一个区域。

题解:
就会这一题写一下题解吧。。。
如果不是环形的话,显然二分+O(n)判断就可以,因为满足单调性。
如果是环形,我们需要枚举起点,所以复杂度成了n*n*logn 
但是我们考虑优化判断的时间复杂度,因为a是一个单调递增的数组,所以我们照样可以lower_bound下一段>当前二分值的区间。复杂度变为n*log2n
代码:
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<vector>
 8 #include<map>
 9 #include<set>
10 #include<queue>
11 #include<string>
12 #define inf 1000000000
13 #define maxn 200000+100
14 #define maxm 500+100
15 #define eps 1e-10
16 #define ll long long
17 #define pa pair<int,int>
18 #define for0(i,n) for(int i=0;i<=(n);i++)
19 #define for1(i,n) for(int i=1;i<=(n);i++)
20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
22 #define mod 1000000007
23 using namespace std;
24 inline ll read()
25 {
26     ll x=0,f=1;char ch=getchar();
27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
28     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n;
32 ll a[2*maxn];
33 inline bool check(ll x,int y)
34 {
35     int xx=lower_bound(a+y,a+y+n,a[y-1]+x)-a;
36     if(xx>=y+n)return 0;
37     int yy=lower_bound(a+xx+1,a+y+n,a[xx]+x)-a;
38     if(yy>=y+n)return 0;
39     return a[n+y-1]-a[yy]>=x;
40 }
41 int main()
42 {
43     freopen("input.txt","r",stdin);
44     freopen("output.txt","w",stdout);
45     n=read();ll sum=0;
46     for1(i,n)a[i]=a[n+i]=read(),sum+=a[i];
47     for1(i,n<<1)a[i]+=a[i-1];
48     ll ans=0;
49     for1(i,n)
50     {
51         if(!check(ans,i))continue;
52         ll l=ans,r=sum,mid;
53         while(l<=r)
54         {
55             mid=(l+r)>>1;
56             if(!check(mid,i))r=mid-1;else l=mid+1;
57         }
58         ans=max(ans,r);
59     }
60     printf("%lld
",ans);
61     return 0;
62 }
View Code