P1873 [COCI 2011/2012 #5] EKO / 砍树 题解

其实这是一篇多题的题解,放在一起了。

P5019 [NOIP2018 提高组] 铺设道路 && P1969 [NOIP2013 提高组] 积木大赛 && P3078 [USACO13MAR] Poker Hands S

大的肯定包含小的,所以只需两项两项考虑,大的单独填。
这里注意,和以前有一题求增大后减小的策略是不一样的。那一题(我忘了什么题qaq)借助了栈。

#include<bits/stdc++.h>
using namespace std;
int n,road[100001];
long long cnt;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&road[i]);
	for(int i=1;i<=n;i++){
		if(road[i]>road[i-1]) cnt+=road[i]-road[i-1];
	}
	printf("%lld",cnt);
	return 0;
}

P1873 [COCI 2011/2012 #5] EKO / 砍树

这题有二分做法(我也是写的二分),但是在这里讲一下贪心(其实也不是贪心,但我叫它贪心)。

肯定是需要单调性的,所以从大到小排序。考虑我们砍到第 i 棵树,那么我们长度就增加了 (i1)×(aiai1) 。其实也就是说在砍的最低高度之上所有的差分都是要砍掉的,所以我们分成一个一个的矩形来看。所以我们砍到哪一棵树停止,哪一棵树的高度就可以作为基准,再加上我们多看砍的就是答案。

二分代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,h[1000005],l,r,mid,hi;
long long len;
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&h[i]);
		hi=max(hi,h[i]);
	}
	l=1,r=hi;
	while(l<=r){
		mid=(l+r)/2;
		len=0;
		for(int i=1;i<=n;++i){
			if(h[i]>mid) len+=h[i]-mid;
		}
		if(len<m) r=mid-1;
		else l=mid+1;
	}
	printf("%d",l-1);
	return 0;
} 

贪心代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,pos,temp;
int a[1000005];
bool cmp(int a,int b){
	return a>b;
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	sort(a+1,a+n+1,cmp);
	for(pos=2;pos<=n&&temp<m;++pos) temp+=(pos-1)*(a[pos-1]-a[pos]);
	printf("%d",a[pos-1]+(temp-m)/(pos-2));
	return 0;
}

现写的,热乎呢。还是很好写的。

P6446 [COCI2010-2011#1] TABOVI

#include<bits/stdc++.h>
using namespace std;
int n,a[1005],b[1005],ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<=n;++i) scanf("%d",&b[i]),a[i]=b[i]-a[i];
	for(int i=1;i<=n;++i){
		if(a[i]>0&&a[i-1]>0) ans+=max(0,a[i]-a[i-1]); 
		else if(a[i]<0&&a[i-1]<0) ans+=max(0,a[i-1]-a[i]);
		else ans+=abs(a[i]);
	}
	printf("%d",ans);
	return 0;
}

P2440 木材加工

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[100005];
bool check(int x){
	int ans=0;
	for(int i=1;i<=n;++i) ans+=a[i]/x;
	return ans>=m; 
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	int l=0,mid,r=1e8+1;
	while(l<r){
		mid=(l+r+1)>>1;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	printf("%d",l);
	return 0;
}

P1182 数列分段 Section II

check 里贪心一下,如果超过 x++num,最后判断 num>m?

#include<bits/stdc++.h>
using namespace std;
int n,m,l,mid,r;
int a[100005];
bool check(int x){
	int num=1,temp=0;
	for(int i=1;i<=n;++i){
		if(temp+a[i]>x) ++num,temp=a[i];
		else temp+=a[i];
		if(num>m) return false;
	}
	return true;
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]),l=max(l,a[i]),r+=a[i];
	while(l<r){
		mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	printf("%d",l);
	return 0;
}
posted @   mountzhu  阅读(89)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示