增援前线

增援前线

(20) 分做法

考虑暴力。答案为(a_i)的和

(50) 分做法

枚举全排列

(100) 分做法

我们可以用二分法或贪心。

这里会用到一个性质。

说人要尽量走得远一点。什么意思?为什么?

画一个图:

360截图175711156810982.jpg

假设:(L=4)

比如说这个魂师,他有 (2) 种选择,现在我们的结论是走最远的最优。

那么,我们看他走近的

360截图175711156810982.jpg

都没路走了,只能还是走远端的那片叶子,所以相当于浪费了一片叶子。

走远的

360截图175711156810982.jpg

还能走,那么我想用这个例子说明什么呢?

我们走得越远,选择越多。

从贪心的角度来讲,要让所有魂师消耗的叶子数量尽量少。

二分

利用刚刚所讲的性质,我们用二分来写。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
    T RR=1;FF=0;char CH=getchar();
    for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    FF*=RR;
}
template<typename T>inline void write(T x){
    if(x<0)putchar('-'),x*=-1;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
template<typename T>inline void writen(T x){
    write(x);
    puts("");
}
int l,r=1,a[100010],b[100010],L,n;//左闭右开,r=1
bool check(int mid){
    memset(b,0,sizeof(b));//a[i]表示的是每个格子的上限,b[i]表示的是每个格子现有的数量
    b[0]=mid;a[n]=mid;
    for(int i=0;i<n;i++){
        for(int j=min(i+L,n);j>=i+1;j--)//从远的开始试
            if(b[j]<a[j]){
                if(b[j]+b[i]<=a[j]){//全部都能去,那么就全部都去
                    b[j]+=b[i];//移走
                    b[i]=0;//变成零
                    break;
                }else{
                    b[i]-=a[j]-b[j];//能塞,尽量塞
                    b[j]=a[j];//塞满
                }
            }
        if(b[i]!=0)return false;//有人没去处,就代表不可能
    }return true;//可能
}
int main(){
    read(n);read(L);
    for(int i=1;i<n;i++){
        read(a[i]);
        r+=a[i];
    }
    while(l+1<r){
        int mid=(l+r)>>1;
        if(check(mid))l=mid;
        else r=mid;
    }cout<<l;
    return 0;
}

贪心

我们发现,上面的二分似乎没什么用,知道答案也未必更好算。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
    T RR=1;FF=0;char CH=getchar();
    for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    FF*=RR;
}
template<typename T>inline void write(T x){
    if(x<0)putchar('-'),x*=-1;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
template<typename T>inline void writen(T x){
    write(x);
    puts("");
}
int a[100010],b[100010],L,n,s;
int main(){
    read(n);read(L);
    for(int i=1;i<n;i++){
        read(a[i]);
        s+=a[i];//一样的道理
    }
    b[0]=s;a[n]=s;//拿边界
    for(int i=0;i<n;i++){
        for(int j=min(i+L,n);j>=i+1;j--)//从远的开始试
            if(b[j]<a[j]){
                if(b[j]+b[i]<=a[j]){//全部都能去,那么就全部都去
                    b[j]+=b[i];//移走
                    b[i]=0;//变成零
                    break;
                }else{
                    b[i]-=a[j]-b[j];//能塞,尽量塞
                    b[j]=a[j];//塞满
                }
            }
    }cout<<b[n];
    return 0;
}

原文链接: https://www.cnblogs.com/zhaohaikun/p/12518886.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    增援前线

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/374287

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月3日 下午12:06
下一篇 2023年3月3日 下午12:06

相关推荐