首页 > 其他分享 >【CSP试题回顾】202303-2-垦田计划(优化)

【CSP试题回顾】202303-2-垦田计划(优化)

时间:2024-03-24 11:58:22浏览次数:18  
标签:垦田 开垦 feildList long maxTi 时间 202303 ti CSP

CSP-202303-2-垦田计划

关键点:二分查找

在这个问题中,有一系列的田地需要在特定的时间 t i t_i ti​ 之后开垦,每块田地的开垦成本为 c i c_i ci​。目标是确定最早的一天,使得在不超过给定的资源 m m m 的情况下,可以开始开垦所有田地。

1.暴力枚举

  • 时间复杂度是 O ( N ) × N O(N) \times N O(N)×N,其中 N N N 是时间范围的大小,因为它需要逐一检查每一天,直到找到满足条件的一天。在最坏的情况下,这意味着可能需要检查所有的天数。

2.二分查找

  • 时间复杂度是 O ( l o g N ) × N O(logN) \times N O(logN)×N,这里的 N N N 也是时间范围的大小。二分查找通过每次排除一半的搜索范围来缩小可能的解空间,因此搜索所需的步骤数量是对数级别的。这在大范围搜索时显著减少了计算量。

通过二分查找,我们能够有效减少必要的计算步骤,从而快速定位到满足条件的最早开始开垦的时间。与暴力枚举相比,二分查找大幅减少了所需的时间,特别是在可能的时间范围很大时,这种时间复杂度的优化尤为显著。

解题思路

  1. 初始化变量: 农田数量 n n n,可用资源 m m m,开垦一块区域的最少天数 k k k,最大时间点 maxTi(初始设为-1),天数列表 dayList 和农田列表 feildList。每块农田用一个结构体 feild 来表示,包括开垦时间点 ti 和成本 ci

  2. 读入数据/构建搜索范围:main 函数中,代码读取农田数量、可用资源、开始时间,并为每块农田读取开垦时间和成本,同时更新最大开垦时间 maxTi。根据农田的开垦时间点生成一个时间列表 dayList,这个列表从开垦一块区域的最少天数 k 到最大时间 maxTi。这个列表代表可能的完成开垦的所有天数。

  3. 二分搜索: 使用二分搜索找出最小的满足条件的时间。在 binarySearch 函数中,设置左右边界 leftright,并通过迭代减少搜索范围来找到最早的一天,从那一天开始,可以在不超出资源 m m m 的情况下完成所有农田的开垦。这是通过计算每一天剩余需要开垦的农田所需的总成本 sumDay 来判定的。

  4. 检查条件: 在二分搜索过程中,每次计算中间点 mid 的资源总和 sumRes。如果 sumRes > m,说明资源不足,需要推迟开垦时间(即增大 left)。如果 sumRes <= m,则检查是否可以将时间提前(即减小 right)。特别的,当 sumRes <= m 且下一天(mid - 1)所需资源超过 mmid 等于起始时间 k 时,找到了满足条件的最早时间,此时输出该时间并结束搜索。

  5. 输出结果: 当找到满足条件的最早时间时,即在不超出预算的情况下,最早可以完成所有农田开垦的时间,输出这一天。

完整代码

【100分思路-二分查找】

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

struct feild
{
	long long ti, ci;
};

long long m, n, k, maxTi = -1;
vector<long long>dayList;
vector<feild>feildList;

long long sumDay(int t) {
	long long sumResource = 0;
	for (auto& it : feildList)
	{
		if (t < it.ti)
			sumResource += (it.ti - t) * it.ci;
	}
	return sumResource;
}

void binarySearch(vector<long long>& arr) {
	long long left = 0;
	long long right = arr.size() - 1;
	while (left <= right) {
		long long mid = left + (right - left) / 2; // 避免溢出
		long long sumRes = sumDay(mid);

		if (sumRes > m) {
			left = mid + 1; // 调整左边界
		}
		else if (sumRes <= m) {
			right = mid - 1; // 调整右边界
		}

		if ((sumRes <= m && sumDay(mid - 1) > m) || mid == k) // 终止条件
		{
			cout << mid;
			return;
		}
	}
}

int main() {
	cin >> n >> m >> k;
	feildList.resize(n);
	for (size_t i = 0; i < n; i++)
	{
		cin >> feildList[i].ti >> feildList[i].ci; 
		maxTi = max(maxTi, feildList[i].ti);
	}
	for (size_t i = k; i <= maxTi; i++)
	{
		dayList.push_back(i);
	}
	binarySearch(dayList);

	return 0;
}

【70分思路-暴力枚举】

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

struct feild
{
	int ti, ci;
};
int m, n, k, maxTi = -1;

int main() {
	cin >> n >> m >> k;
	vector<feild>feildList(n);
	for (size_t i = 0; i < n; i++)
	{
		cin >> feildList[i].ti >> feildList[i].ci;
		maxTi = max(maxTi, feildList[i].ti);
	}
	for (size_t i = k; i < maxTi; i++)
	{
		long long sumResource = 0;
		for (auto& it : feildList) 
		{
			if (i < it.ti) sumResource += (it.ti - i) * it.ci;
		}
		if (sumResource <= m)
		{
			cout << i;
			break;
		}
	}
	return 0;
}

标签:垦田,开垦,feildList,long,maxTi,时间,202303,ti,CSP
From: https://blog.csdn.net/fzy2003/article/details/136983983

相关文章

  • P9755 [CSP-S 2023] 种树
    P9755[CSP-S2023]种树首先,容易看出单调性,可以对最少天数二分。转为判定性问题后,我们思考如何判定。对于每棵树,都可以从刚种下长到最后一天。我们由此可以写出\(calc(i,l,r)\)表示第\(i\)棵树从第\(l\)天长到第\(r\)天的高度。\(calc(i,l,r)=\sum\limits_{i=l}^r\max(......
  • P5657 [CSP-S2019] 格雷码
    #include<iostream>#include<stdio.h>#include<algorithm>#include<string>#include<cmath>#defineFor(i,j,n)for(inti=j;i<=n;++i)usingnamespacestd;typedefunsignedlonglongUll;constunsignedlonglo......
  • P5664 [CSP-S2019] Emiya 家今天的饭 题解
    题目链接:P5664[CSP-S2019]Emiya家今天的饭思路:显然可以算出总数减去不合法的,不合法即有一列超过一半,显然最多一列,枚举这一列。考虑dp,设\(f(i,j,k)\)表示前\(i\)个方法,\(j\)个这一列,\(k\)个其他列。但是这样是\(O(n^3m)\),我们需要优化。显然我们只关心\(j,k\)相......
  • NXP ECSPI controller简介
    spi协议可参考:https://www.cnblogs.com/lethe1203/p/18083528 ECSPI(EnhancedConfigurableSerialPeripheralInterface)是由NXPSemiconductors(原飞利浦半导体部门)开发的,imx6ull上一共有四组spi接口,每组寄存器都是一样的,都是以第一组为例。 典型的SPIBURST传输图: ECSP......
  • LY1169 [ 20230328 CQYC省选模拟赛 T1 ] 传奇特级超空间
    题意设\(f_{n,m}\)表示\(m\)维空间能被\(n\)个\(m-1\)维空间划分的最大区域数。求\(\sum_{i=0}^mf_{n,i}\)\(n,m\le10^{18},p\le2\times10^7\)Sol注意到:\(f_{n,m}=f_{n-1,m-1}+f_{n-1,m}\)。不难想到\(f\)应该是组合数的前缀......
  • 【CSP考点回顾】C++标准库加速输入输出
    C++标准库加速输入输出ios_base::sync_with_stdio(false);:取消C++标准库(iostream)与C标准库(stdio)之间的同步。默认情况下,为了保证C++的cin、cout与C的stdin、stdout能够互相交换数据,它们之间会进行同步。这样做虽然安全,但会减慢IO操作的速度,因为每次IO操作都需要进行同步。......
  • CSPJ知识点整理
    指针:https://blog.csdn.net/qq_35429198/article/details/109331937排序:https://www.cnblogs.com/myeln/articles/17576193.html递归作业:https://www.luogu.com.cn/training/370327#problems哈夫曼编码:https://zhuanlan.zhihu.com/p/415467000图:https://www.luogu.com.cn/trai......
  • LY1165 [ 20230324 CQYC省选模拟赛 T3 ] 迷雾
    题意求有多少种长度为\(N\)的满足以下条件的序列。是一个\(1\simN\)的排列。至少进行\(K\)次操作后,该序列才含有一个元素。\(N\le1000\)Sol首先因为序列是一个排列,所以操作次数不会太多。操作次数大概在\(\logN\)的级别。不难注意到对于一个数列,剩下的只......
  • csproj技巧
    1、在项目中我们经常写string?Message{get;set;}明明是引用类型,它底下还是会出现波浪线,我们可以打开csproj找到Nullable将它改为disable,或者删除,它默认是disable<Nullable>disable</Nullable>2、我们的WPF中可能会使用到Winform的类库,添加UseWindowsForms,一定要写在UseWPF......
  • LY1168 [ 20230325 CQYC省选模拟赛 T3 ] 游戏
    题意给定\(n\)个区间\(l_i,r_i,k_i\)。\(k_i\)表示解锁当前点当且仅当\(l_i\tor_i\)的区间内至少有\(k_i\)个点被解锁。问一共能解锁多少点。Sol直接暴力跑是\(n^2\)的。不难想到优化建图,复杂度:\(O(nk\log)\)这样明显是过不去的。集中注意力。注意到操......