增援前线

增援前线

2020 分做法

考虑暴力。答案为aia_i的和

5050 分做法

枚举全排列

100100 分做法

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

这里会用到一个性质。

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

画一个图:

假设:L=4L=4

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

那么,我们看他走近的

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

走远的

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

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

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

二分

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

#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/12817030.html