Dinner 点餐

来源:互联网 发布:中欧工程技术学院知乎 编辑:程序博客网 时间:2024/05/16 05:29

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

二分答案。
关键在于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 50009using 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 50009using 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 50009using 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;}