2019暑假集训8.22(problem2.dinner)(二分)

因为求最大时间的最小,考虑到二分答案。

常规思路:断环为链,二倍链。

最暴力的做法是在n个位置都断一次环,序列for一遍暴力分组,大于mid了就分到下一组,时间O(n^2 logn)

考虑优化:

我们发现每一次暴力分组是把整个序列都给走了一遍,分好的组满足和<=mid,与其一个个的把值加到和里,不如先处理出前缀和,然后对于每一个组的起点,二分找出这个组的终点(我代码中是用upper_bound实现的)

int s=t[q],c=1;//s即为起点
int flagg=0;
for(int i=q;i<=q+n-1;++i)
{
    if(c>mid){flagg=1;break;}
    if(t[i]>mid)return 1;
    int v=mid-s;//还有这么多才到mid
    v+=sum[i];//在前缀和数组中查找,所以加上sum[i]
    int pos=upper_bound(sum+i,sum+2*n+1,v)-sum;//在i之后进行寻找
    if(pos>q+n-1)break;
    i=pos-1;//循环完后还要++i,所以这里i=pos-1
    if(t[pos]<=mid)s=t[pos],c++;
    else return 1;
}

然鹅这样最后的点还是会T,再考虑优化

我们在每次的新断的链进行操作前加了一句这样的话:

if(sum[q]>mid)return 1;

即起点的前缀和小于mid的话,这样断开的链一定是不满足的。

为什么?

我们看这样一组数据

假如二分的答案mid=11

试着模拟一下算法过程,断的链分别是

1 5 2 7 8

5 2 7 8 1

2 7 8 1 5

到7 8 1 5 2这一组时一定是不满足的(假设前面的也不满足所以一直向后走)

因为1 5 2 7 8是不满足的(且1 5 2 分为了一组),所以才会往后断环,到了7 8 1 5 2 仍是会1 5 2 分为一组还是不满足,就相当于是把1 5 2 7 8 分成的组调了一下顺序而已。

#include<bits/stdc++.h>
#define N 50003
#define M 3003
#define INF 2100000000
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x*f;
}
int t[2*N],sum[N*2],n,m;
int check(int mid)
{
    int q=1;
    while(q<=n)
    {
        if(sum[q]>mid)return 1;//!!!当前面的前缀和>mid还不成功,这种情况在开始枚举时已经失败,于是此mid不成立
        int s=t[q],c=1;//s即为起点
        int flagg=0;
        for(int i=q;i<=q+n-1;++i)
        {
            if(c>mid){flagg=1;break;}
            if(t[i]>mid)return 1;
            int v=mid-s;//还有这么多才到mid
            v+=sum[i];//在前缀和数组中查找,所以加上sum[i]
            int pos=upper_bound(sum+i,sum+2*n+1,v)-sum;//在i之后进行寻找
            if(pos>q+n-1)break;
            i=pos-1;//循环完后还要++i,所以这里i=pos-1
            if(t[pos]<=mid)s=t[pos],c++;
            else return 1;
        }
        if(flagg==0&&c<=m&&s<=mid)return 0;
        q++;//重新断环
    }
    return 1;
}
int main()
{
//    freopen("dinner.in","r",stdin);
  //  freopen("dinner.out","w",stdout);
    n=read(),m=read();
    int l=0,r=0;
    for(int i=1;i<=n;++i)
    {
        t[i]=read();
        sum[i]=sum[i-1]+t[i];
        r+=t[i];
    }
    for(int i=n+1;i<=2*n;++i)
      t[i]=t[i-n],sum[i]=sum[i-1]+t[i];
    int ans;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid))l=mid+1;
        else ans=mid,r=mid;
    }
    printf("%d\n",ans);
}
/*
5 5
1 2 5 4 3

5 2
1 5 2 7 8

10 4
1 3 5 2 7 8 2 1 2 4
*/

也还有倍增的做法

原文地址:https://www.cnblogs.com/yyys-/p/11395983.html

时间: 2024-08-30 13:34:48

2019暑假集训8.22(problem2.dinner)(二分)的相关文章

「总结」2019暑假集训

啊,我最喜欢的暑假集训终究还是结束了. 感觉集训收获的还是挺大的,不管是在知识方面还是心态方面,感觉现在考试心态稳了很多,不管是考前考时考后,都可以很快的调整了.大概就是教练所说的考试心态调整的加速.最近感觉非常好,虽然水题还是老爆零,考得也不怎么样,不过我的确是飞快的在进步了,只要我在进步就好了,我很心满意足的. 总结一下接近30场的考试吧. 一开始的7场一直只有50分左右,而且还有两次没有交卷子,气得我把纸贴在电脑上提醒自己交卷子,虽然成绩并不怎么样,不过我还好在也不犯这个错误了. 然后就理

2019暑假集训8.24(problem2.baritone)(链表(巧妙数据结构))

数据结构好题! 因为思路是第一次见,所以就直接说思路. 题目抽象: 这是一个矩形 里面有很多的点,求至少覆盖k个点的矩形有多少个 先确定上边界,下边界为低端 上边界下面的点用链表存起来 考虑以每个点作为左边界的贡献(线上的点也算在矩形内),假如k=3,那么右边界至少在橙色这根线这儿 符合要求的矩形的左边界范围L和右边界范围R如图 做出的贡献为L*R,如果前面还有点注意是左开右闭(因为右边到底都是可以的) 然后移动左边界 到下一个点再计算贡献 再来移动下边界 一些点可能在同一水平线上,所以一开始可

2019暑假集训 8/2

学习内容:线段树+可持久化线段树 今日完成题数(不包含多校):5 /*多校补题情况(之前定的每支队伍标准):?*/ 今日看书情况:3页 学习算法的总结 可持久化线段树一直没有好好研究 直到最近着重开始写线段树专题 写了一些权值线段树 才把之前有的疑问的解决了 今日做题总结    hdu-6183 https://www.cnblogs.com/MengX/p/11291321.html hdu-4630 https://www.cnblogs.com/MengX/p/11291349.html

2019暑假集训DAY1(problem3.play)(单调栈思想)

题面 play 题目大意 这个位面存在编号为1~2N的2N个斗士,他们正为争夺斗士大餐展开R轮PVP,每个斗士i都有一个固有APM ai,和一个初始斗士大餐储量 bi.每轮开始前以及最后一轮结束之后,2N个斗士会重新按照各自斗士大餐的储量进行排序(斗士大餐储量相同时编号小的靠前),每轮中,第1名和第2名PVP,第3名和第4名PVP,……第2k-1名和第2k名PVP,第2N-1名和第2N名PVP.而每场一对一的PVP都非常无聊,总是两个斗士中APM高的获胜,另一方失败:或者APM相同的两方取得平手

2019暑假集训 Intervals

题目描述 给定n个闭区间[ai,bi]和n个整数ci.你需要构造一个整数集合Z,使得对于任意i,Z中满足ai<=x<=bi的x不少于ci个.求Z集合中包含的元素个数的最小值. 输入 第一行为一个整数n(1<=n<=50000) 接下来n行每行描述一个区间,三个整数分别表示ai,bi和ci.( 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1.) 输出 输出一个整数,表示Z中包含元素个数的最小值. 样例输入 5

2019暑假集训 数字游戏

题目描述 科协里最近很流行数字游戏.某人命名了一种不降数,这种数字必须满足从左到右各位数字成小于等于的关系,如123,446.现在大家决定玩一个游戏,指定一个整数闭区间[a,b],问这个区间内有多少个不降数. 输入 有多组测试数据.每组只含两个数字a,b,意义如题目描述. 输出 每行给出一个测试数据的答案,即[a,b]之间有多少不降数. 样例输入 1 9 1 19 样例输出 9 18 提示 对于全部数据,1<=a<=b<=2^31-1. 裸的数位dp,每一位从上一位开始搜即可(保证不下降

2019暑假集训 8/16

学习内容:网络流 今日完成题数(不包含多校): 今日看书情况:无 学习算法的总结 有上下界的网络流 和 最小费用可行流 今日做题总结 总结 今日心得: https://blog.csdn.net/forever_dreams/article/details/81879277 https://blog.csdn.net/qq_43202683/article/details/90049597 明日任务:   明天写完基础的可行流题目 就可以写一写gym的进阶题 原文地址:https://www.c

2019暑假集训 文件压缩

题目背景 提高文件的压缩率一直是人们追求的目标.近几年有人提出了这样一种算法,它虽然只是单纯地对文件进行重排,本身并不压缩文件,但是经这种算法调整后的文件在大多数情况下都能获得比原来更大的压缩率. 题目描述 该算法具体如下:对一个长度为nn的字符串SS,首先根据它构造nn个字符串,其中第ii个字符串由将SS的前i-1i−1个字符置于末尾得到.然后把这nn个字符串按照首字符从小到大排序,如果两个字符串的首字符相等,则按照它们在SS中的位置从小到大排序.排序后的字符串的尾字符可以组成一个新的字符串S

2019暑假总结7.15-8.23+大一总结

2019暑假集训7.15-8.23 今年大一下学期整个暑假基本上是了解学习了dp.动态规划.线段树.树状数组.贪心.搜索.背包问题.记忆化搜索.欧拉回路.最大流.最短路.最小生成树.二叉搜索树.kmp.数论..马拉车等,感觉每天在敲代码,可是整体看下来学的东西很少,但是谢谢题目又是好久才能写出一道题. 等到明天九月二号一来到,我就是大二的学生了,大二这整一年是最关键的一年,一定要加油加油. 原文地址:https://www.cnblogs.com/OFSHK/p/11444186.html