CCF- CSP 202303-2垦田计划 【多种方法】满分题解
70分思路:
- 从基础耗时最长的区域进行筛选,每次基础耗时减少一天
- 该方法以
m
作为参考对象,对m
进行减的操作(m
的数据范围达到1e9
,导致超时) - 采用优先队列作为存储结构,同时存储
t
和c
代码如下:
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n,m,k;
typedef pair<int,int>PII;//采用pair同时存储t和c
priority_queue<PII,vector<PII> > heap;//采用优先队列
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
int t,c;
cin>>t>>c;
heap.push({t,c});//压入队列
}
while(m>0)
{
PII t = heap.top();//取出当前基础耗时最大的
heap.pop();//记得删除最大点
//如果最大值不满足条件
if(t.first<=k)
{
heap.push(t);
break;
}
m -=t.second;//每次只缩减一天
t.first -= 1;
heap.push(t);
}
cout<<heap.top().first<<endl;//输出基础耗时最大的值
return 0;
}
100分思路1:
- 在70分思路的基础上,发现超时的原因:
m
的数据范围达到了1e9
,造成超时 - 可能改进的方法:按照基础耗时的大小进行筛选,一次循环缩减大量资源。而不是像70分代码思路:一次只减少一天的资源量
- 从基础耗时最小值
k
,最大值mx
进行筛选,一次操作可以使m
的值大量减少 - 采用二分算法,对所有可能的耗时进行搜索(范围为
k~mx
),找到最短耗时
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n,m,k;
int t[N],c[N];
int mx;//记录最大天数
//判断当前耗时天数x能否满足需求
bool jude(int x)
{
int sum = 0;//记录资源总和
for(int i=1;i<=n;i++)
{
if(t[i]<x)continue;//基础耗时小于x,不需要考虑资源消耗
sum+=(t[i]-x)*c[i];//sum的值进行改变
if(sum>m)return false;//如果资源总和大于m,不满足条件
}
return true;
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
cin>>t[i]>>c[i];
mx = max(mx,t[i]);
}
int l=k,r=mx;//二分:左边起点为l,右边为mx
while(l<=r)
{
int mid = (l+r)>>1;
if(jude(mid)) r=mid-1;//满足条件,往小范围搜索
else l = mid+1;
}
cout<<l<<endl;
return 0;
}
100分思路2:
- 70分思路是对每一个区域单独处理,仔细分析后,发现可以对同一基础耗时的区域同时处理
- 单独开一个数组
sa
用来记录同一基础耗时的区域所需资源总数 - 从
mx
到k
依次处理,每次使得最大基础耗时的区域同时减少一天
代码如下:
#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;
}