Dinner 点餐

这里写图片描述
这里写图片描述

二分答案。
关键在于check()的写法。

20分的写法:
check(x) 中O(n*n)的写法:直接枚举起点,一直往后加,一旦>x,就加一张菜单,如此枚举。

60分的写法:
二分加二分。用一个前缀和来优化。
check(x)中枚举起点s,设当前这一张菜单的起点为L,那么下一个起点就是sum[L]+x的前驱,可以用upper_bound()来找,然后再把找出来的那个位置减 1 ,就是下一个起点L,菜单数加 1。直到L>=s+n就停止。再把菜单数与m进行比较。

100分的写法
在20分的基础上加上一句优化。

for(int s=1;skp<=x;s++,skp+=t[s])

check

int check(LL x)
{
    int tt; 
    LL p,skp=0;
    for(int s=1;skp<=x;s++,skp+=t[s])
    {
        tt=1,p=t[s];
        for(int i=s+1;i<s+n;i++) 
        {
            if(p+t[i]>x) 
            {
                p=t[i];
                tt++;
            }
            else p+=t[i];
        }
        if(tt<=m) return true; //只要有成立的,就要缩小答案
    }
    return false;
}

见图
这里写图片描述

skp( B这一段) 如果>x,一定会在后面使用一个菜单,那么就相当于在前面时B使用菜单一样,如果这样成立的话,那么在前面枚举s是也会成立,运行到这一步,就说明前面不成立,那么现在也不会成立;

20分代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define N 50009
using namespace std;
int n,m,t[2*N];
LL L,R,mid;
bool check(LL x)
{
    int tt; 
    LL p;
    for(int s=1;s<=n;s++)
    {
        tt=1,p=t[s];
        for(int i=s+1;i<s+n;i++) 
        {
            if(p+t[i]>x) 
            {
                p=t[i];
                tt++;
            }
            else p+=t[i];
        }
        if(tt<=m) return true;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&t[i]);
        R+=t[i],L=max(L,1ll*t[i]);
        t[i+n]=t[i];
    }
    while(L<=R)
    {
        mid=(L+R)>>1;
        if(check(mid)) R=mid-1;
        else L=mid+1;
    }
    printf("%lld",L);
    return 0;
} 

60分代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
#define N 50009
using namespace std;
int n,m,t[2*N];
LL L,R,mid,sum[2*N];
bool check(LL x)
{
    int tt,l; 
    for(int s=1;s<=n;s++)
    {
        l=s;tt=0;
        while(l<s+n)
        {
            l=upper_bound(sum+l,sum+s+n+1,sum[l]+mid)-sum-1;
            tt++;
        }
        if(tt<=m) return true;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&t[i]);
        R+=t[i],L=max(L,1ll*t[i]);
        t[i+n]=t[i];
    }
    for(int i=1;i<=2*n;i++) sum[i]+=sum[i-1]+t[i];
    while(L<=R)
    {
        mid=(L+R)>>1;
        if(check(mid)) R=mid-1;
        else L=mid+1;
    }
    printf("%lld",L);
    return 0;
} 

100分代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define N 50009
using namespace std;
int n,m,t[2*N];
LL L,R,mid;
int check(LL x)
{
    int tt; 
    LL p,skp=0;
    for(int s=1;skp<=x;s++,skp+=t[s])
    {
        tt=1,p=t[s];
        for(int i=s+1;i<s+n;i++) 
        {
            if(p+t[i]>x) 
            {
                p=t[i];
                tt++;
            }
            else p+=t[i];
        }
        if(tt<=m) return true;  
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&t[i]);
        R+=t[i],L=max(L,1ll*t[i]);
        t[i+n]=t[i];
    }
    while(L<=R)
    {
        mid=(L+R)>>1;
        if(check(mid)) R=mid-1;
        else L=mid+1;
    }
    printf("%lld",L);
    return 0;
} 
原文地址:https://www.cnblogs.com/dfsac/p/7587800.html