CCF-CSP 202303-2 垦田计划

第一思路是枚举,即枚举所有可能的最小耗时,计算每个耗时的所需资源,如果资源不够了,输出当前最小耗时+1即可

#include<iostream>

using namespace std;

int n,m,k;
typedef struct Node{
	int t,c;
}Node;
Node arr[100005];
int all_need=0;
int time_need=-1;

int main(){
	cin>>n>>m>>k;
	for(int i=0;i<n;i++){
		cin>>arr[i].t>>arr[i].c;
		all_need+=(arr[i].c*(arr[i].t-k));
		time_need=max(time_need,arr[i].t);
	}
	if(m>=all_need){//资源是否足够支付将所有区域所需时间降到k 
		cout<<k<<endl;
	}else{
		int ans=0;
		for(int i=time_need-1;i>=k;i--){//让所有区域所需时间减少到<=i 
			int temp=0;
			for(int j=0;j<n;j++){
				if(arr[j].t>i){//所需天数>希望天数 
					temp+=(arr[j].c*(arr[j].t-i));
					if(temp>m)break;//资源不够 
				}
			}
			if(temp>m){
				ans=i+1;//天数+1即答案 
				break;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
} 

当然这里使用了嵌套for循环,时间复杂度为O(n^2),因此只能拿到70分

因此我们需要尝试优化,仔细观察不难发现可以优化的点就在于“枚举希望耗时”,我们可以将线性枚举耗时i,优化为二分枚举耗时i,这样时间复杂度就变为nlogn了即可满分

#include<iostream>
#include<algorithm>
using namespace std;

int n,m,k;
typedef struct Node{
	int t,c;
}Node;
Node arr[100005];
int time_need=-1;

bool check(int time){
	int sum=0;//计算所有区域耗时降到time需要的资源
	for(int i=0;i<n;i++){
		if(arr[i].t<time)continue;//已经比time小了
		sum+=(arr[i].c*(arr[i].t-time));
		if(sum>m)return false;
	} 
	return true;
}

int main(){
	cin>>n>>m>>k;
	for(int i=0;i<n;i++){
		cin>>arr[i].t>>arr[i].c;
		time_need=max(time_need,arr[i].t);
	}
		//尝试在枚举“希望耗时 ”这里进行二分优化
	int left=k,right=time_need;
	while(left<=right){
		int mid=(left+right)/2;
		if(check(mid)){//判断是否所有区域耗时都能达到mid 
			right=mid-1;//尝试更小 
		}else{
			left=mid+1;
		}
	} 
	cout<<left<<endl;
	
	return 0;
} 

满分思路扩展参考自

  • 70分思路是对每一个区域单独处理,仔细分析后,发现可以对同一基础耗时的区域同时处理
  • 单独开一个数组sa用来记录同一基础耗时的区域所需资源总数
  • mxk依次处理,每次使得最大基础耗时的区域同时减少一天
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n,m,k;
int t[N],c[N];
int sa[N];//记录同一基础耗时缩减一天所需要的总资源
int mx;//记录基础耗时的最大值
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>t[i]>>c[i];
        sa[t[i]]+=c[i];//记录同一基础耗时缩减一天所需要的总资源
        mx = max(mx,t[i]);
    }
    int ans = mx;//记录结果
    for(int i=mx;i>=k;i--)
    {
        if(sa[ans]>m)break;
        m-=sa[ans];//同一基础耗时的同时减少一天
        sa[ans-1]+=sa[ans];//下一天的需要加上上一天的资源总数
        //ans的最小值为k
        if(ans>k)
        {
            ans--;
        }
    }
    cout<<ans<<endl;
    return 0;
}

该思路单看代码可能难以理解,建议自己调试一遍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值