码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-08-22 19:02:24      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:upper   序列   pos   代码   ide   答案   bsp   read   opened   

技术图片

技术图片

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

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

最暴力的做法是在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
*/
View Code

 也还有倍增的做法

技术图片

 

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

标签:upper   序列   pos   代码   ide   答案   bsp   read   opened   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!