题解——慕斯蛋糕

Posted ssw02

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解——慕斯蛋糕相关的知识,希望对你有一定的参考价值。

慕斯蛋糕

为了避免某些人通过搜索引擎在考试时找到这篇题解,ssw02魔改了一波题面

这是一道触及ssw02感情的题目,ssw02第一次做这道题时,还是一个刚学最短路的boy,然后看着上一届学长YL现场秒切,而自己几乎天天爆0的生活,然让ssw02感到了无助,最后耽搁了WRY学长半个小时才将这道完全超出知识层面的题目解决,这都是9个月前的事了

所以,非常感谢各位能读一下这篇9个月尘封后的题解。

题面

这道题是私有的,所以我魔改了下。

ys今天过生日,一共有N-1个好朋友,加上ys自己就一共N个人,过生日当然要有很好的气氛,所以大家都围成一圈坐在圆桌旁分慕斯蛋糕。ys一共有M个慕斯蛋糕,分慕斯蛋糕时,每个蛋慕斯糕都可以被切成很多很多小块(就当分不完吧),第i个人拿到一个蛋糕并切出自己的分量需要花费时间T[i]。 当一个人切完之后,就会把慕斯蛋糕传到他右手边的第一个人。 M个慕斯蛋糕是同时发出的,每个慕斯蛋糕只能同时被一个人切分。 ys望知道如何分发蛋糕,才能让大家尽快分到慕斯蛋糕,然后开始过生日?
当然ys是一个温柔的人,并不想为难你,所以你只需要输出最后一个人分到慕斯蛋糕的时间即可。

题目思路:

ssw02先B一句,这是一个环,分发的方案就会产生明显的后效性(及时没有环也有后效性),而且说实话,这道题的数据范围对DP极其不友好,n<=50000。
既然正向解题不行,那我们就把题目转化为一个判定性问题

下面是对一些性质的分析:
1.右手边传,及一个人想要拿到蛋糕,必须从他前面的一个人手中传来,每个人拿到蛋糕是具有顺序性的。
2.M个蛋糕同时发出,那么所传达到的人数一定是随时间的增加而增多的,而对于时间的影响只是分配起点的问题。答案满足单调性。
3.从一个固定起点开始,蛋糕的传递只受到总时间的影响和到达人的T[i]的影响。
4.如果一个人在时间T内无法切完蛋糕,那么这个时间绝对不合法。
5.如果第J人在时间T内可以把蛋糕传给第K个人,第K个人在T内可以传给第H个人,那么,在有两个蛋糕的情况下,时间T内 第J—H的人都可以传到蛋糕。

相信到这里,你已经可以想到二分答案了。但是数据仍然卡住了我们,n<=50000. 0<m<=n
好的,答案的单调性也在启示我们,这道题可以倍增。

到这里,思路理清了。
1.破环为链,开二倍数组。
2.二分答案,即二分时间 t 。
3.处理出每个人在t的时间内向右传到最远的人。
4.倍增处理出M个蛋糕的情况,正确性分析中有说明。

AC code 这个代码,是我刚接触OI 3个月时写过的最难代码,但印象也最深刻。 码风和现在完全不一样,见谅

#include<bits/stdc++.h>
const int N=2000005 ;//开2倍数组 
int  pre[N][17],inf=1e9+7;
int  a[N],sum[N];//本值 前缀和都开 2倍 
int  n,m;
inline int read()

    int s=0,w=1;
    char g=getchar();
    while(g<'0'||g>'9')if(g=='-')w*=-1;g = getchar();
    while(g>='0'&&g<='9')s = s*10+g-'0';g = getchar();
    return s*w;

bool  check (int lim) 

    memset(pre,0,sizeof(pre));
    for (int i=1;i<=n;i++)
        if (a[i]>lim)     //单点超时 false 
            return  false ;
    int k=0;
    for(int i=1;i<=2*n;i++) 
                               
            for (;k<i;k++)
            if (sum[i]-sum[k]<=lim) 
                break;              //即求出最大的合法的k值(最远可以一步走多远) 
        pre[i][0]=k; //每个点在1个蛋糕的情况下,最远跑到k的位置 
    
    for ( int i=1;i<=2*n;i++) 
                               
        for(int j=1;j<=15;j++)// 倍增  要处理le9+7 
            pre[i][j]=pre[pre[i][j-1]][j-1];//递推方程 
            //从上一个k的位置再跑2^j-1 
    
    for(int i=1;i<=2*n;i++) 
    
        int now=i;
        for(int j=15;j>=0;j--)
            if ((1<<j)&m)        //或运算
                now=pre[now][j];
        if (i-now>=n)
        return true ;
    
    return false;


int dx(int l,int r)

    int ans;
    while (l<=r) 
    
        int mid=l+r>>1;
        if(check(mid))r=mid-1,ans=mid;//check当前的mid是否合法 
        else l=mid+1;
    
    printf("%d",ans);


int main() 

    n=read();m=read();//n人 m菜单 
    for(int i=1;i<=n;i++) 
    
    a[i]=read();a[i+n]=a[i];
    
    for(int  i=1;i<=2*n;i++)
    sum[i]=sum[i-1]+a[i]; //前缀和 
    dx(1,inf);//inf=1e9+7 
    return  0 ;

好了,现在非常感谢你耐心读完了这篇博客。接下来,是ssw02的怀念时间。

上一届给ssw02留下深刻影响的学长:YL , WRY , JZ , LJX , FYT , 还有几位实在记不起名字了,抱歉。
谨纪念 ssw02 于2019.7.13

以上是关于题解——慕斯蛋糕的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1190 生日蛋糕题解

#10172. 「一本通 5.4 练习 1」涂抹果酱 题解

luogu1731生日蛋糕题解--恶心剪枝

2019 Rocky Mountain Regional 题解 (6/11)

2019 Rocky Mountain Regional 题解 (6/11)

Wannafly挑战赛13-D