标签:set 搜索引擎 前缀 ons 切分 卡住 class block 顺序
为了避免某些人通过搜索引擎在考试时找到这篇题解,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
标签:set 搜索引擎 前缀 ons 切分 卡住 class block 顺序
原文地址:https://www.cnblogs.com/ssw02/p/11181683.html