zoukankan      html  css  js  c++  java
  • 增援前线

    增援前线

    (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;
    }
    
  • 相关阅读:
    《第三周作业》——第四小组
    《UML与设计原则》--第四小组
    《我与计算机》——第四小组
    PSP数据比较(四则运算)——计应193第6组栗亚文
    个人工作流程(地铁收费系统)——计应193第6组张淑雅
    设计模式学习总结
    行为型模式总结
    UML第二部分和创建型模式的总结(二)
    UML第二部分和创建型模式的总结
    UML第一部分和设计模式原则的总结
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/12518886.html
Copyright © 2011-2022 走看看