• LOJ2758 年轮蛋糕


    JOI 君马上要和妹妹 JOI 子和 JOI 美一起吃小吃。今天的小吃是他们三个人都很喜欢的年轮蛋糕。

    年轮蛋糕是像下图一样呈圆筒形的蛋糕。为了把蛋糕分给三个人,JOI 君必须沿着半径方向切 3 刀,从而把蛋糕分成三块。然而,由于年轮蛋糕硬得像实木一样,要让刀切进去并不简单。因此,这个年轮蛋糕上事先准备了 N 个切口,而 JOI 君只能在有切口的位置下刀。切口按顺时针顺序编号为 1到 N,对于 1≤i≤N−1,第 i 个切口和第 i+1个切口之间部分的大小是 Ai。第 N 个切口和第 1个切口之间部分的大小是 AN ​​。

    图 1:一个年轮蛋糕的例子,N=6,A1=1,A2=5,A3=4,A4=5,A5=2,A6=4

    妹控的 JOI 君在把蛋糕切成 3 块之后,自己选走最小的一块吃掉,把剩下两块分给两个妹妹。而另一方面,JOI 君太喜欢年轮蛋糕了,只要能吃到的时候就会想吃很多很多。试求:最小块的大小不超过多少。

    样例说明 1


    图 2:从第 1,3,5个切口下刀时是最优解(即图中粗实线位置)。

    这道题用二分+二分。我们知道分一个蛋糕需要切三刀,第一刀枚举O(n),第二刀二分logN,第三刀二分logN,一共O(nlogn^2),可以过。

    第一、二刀会把最小的一块给切走,然后留下一大块。

    然后用第三刀切这一大块,如果这两块切完都比刚才切走的小,说明这一大块无论怎么切都切不出符合的结果,所以开始的一块切大了,第二刀往小切

    如果前面一块小于刚切走的,说明第三刀要往后切;

    如果后面一块小了,就往前切;

    如果两块都可以,说明这种切法可行,第二刀尝试往更大的切。

    注意所有数组下表的处理。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <stack>
    #define in(a) a=read()
    #define MAXN 200020
    #define REP(i,k,n) for(long long i=k;i<=n;i++)
    using namespace std;
    inline long long read(){
        long long x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar())
            if(ch=='-')
                f=-1;
        for(;isdigit(ch);ch=getchar())
            x=x*10+ch-'0';
        return x*f;
    }
    long long n;
    long long ans;
    long long a[MAXN],s[MAXN];
    inline bool check(long long i,long long k){
        long long sum=s[i+k-1]-s[i-1];
        long long loc=i+k-1;
        long long left=0,right=n;
        while(right-left>1){
            long long mid=(right+left)/2;
            if(s[loc+mid]-s[loc]<sum && s[i+n-1]-s[loc+mid]<sum)  return 0;
            if(s[loc+mid]-s[loc]<sum)  left=mid;
            if(s[i+n-1]-s[loc+mid]<sum)  right=mid;
            if(s[loc+mid]-s[loc]>=sum && s[i+n-1]-s[loc+mid]>=sum)  return 1;
        }
        return 0;
    }
    int main(){
        in(n);
        REP(i,1,n){
            in(a[i]);
            a[i+n]=a[i];
            s[i]=s[i-1]+a[i];
        }
        REP(i,1,n)
            s[i+n]=s[i+n-1]+a[i+n];
        REP(i,1,n){
            long long left=0,right=n;
            while(right-left>1){
                long long mid=(left+right)/2;
                if(check(i,mid))  left=mid;
                else  right=mid;
            }
            ans=max(s[i+left-1]-s[i-1],ans);
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    Adobe Flash Player 设置鼠标点不到允许或者拒绝!
    bzoj2096
    bzoj2789
    LA3353
    poj2594
    bzoj2427
    bzoj1076
    bzoj2818
    bzoj3668
    bzoj2006
  • 原文地址:https://www.cnblogs.com/jason2003/p/9737402.html
Copyright © 2020-2023  润新知