P1484 种树 - 堆 - 贪心

本文探讨了一种利用堆和缩点技术解决特定选择问题的方法,通过递推思路,将问题简化为一个个子问题,最终实现高效求解。文章详细介绍了如何通过缩点处理多个点的影响,以及如何在代码中实现这一过程。

这题想得脑阔疼。。。我只想到可以选一个点,或者不选这个点选其左右两个点的和

先来特殊情况,k=1, 然后k=2
可以发现由1到2的过程中,可以是一个本来被选的点,替换为他左右两边的点,收益增加了a[pos+1] + a[pos-1] - a[pos]
这个题是一个个选,直到选了k个,有种递推的感觉,先确定种了前面几个,再确定这一个该怎么种

然后我不会处理若有别的点也选上,并且影响到这个pos+1和pos-1的情况

事实上可以把这三个点缩在一起啊(当然不能提前缩,要在pos这个点被选时缩起来)
然后我若再选一个别的点,若这个别的点会影响到pos+1或pos-1,因为缩了点,pos+1和pos-1现在都在pos上,所以这个“别的点”就会让pos的值不可用,由于我们把值也缩在pos上了,直接导致这个pos替换为pos+1和pos-1不可用了,这也符合题意,并且更好写
但是还是有点难处理怎么缩点,缩点之后应当删除3个点,新建一个点,而原来其他位于这三个点左边最靠右的点,若我们选了这个点,这说明这三个点就不可选了,也就是新点不可选,所以要把原来位于左边最靠右的点的右边连到新点上,这就需要开几个数组模拟链表什么的了

堆的题拆点(一个点拆成两个,可以是等大的两个,对左右两边起一个桥梁作用)和缩点(删点)比较多

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 1000000 + 10;
typedef long long ll;
ll n,k,a[MAXN],ans,flg[MAXN],cnt,l[MAXN],r[MAXN]; 
bool fina;
struct node{
	int val, pos;
	bool operator < (const node & a) const {
		return val < a.val;
	}
};
priority_queue<node> q;
int main() {
	scanf("%lld%lld", &n, &k);
	for(int i=1; i<=n; i++) {
		scanf("%lld", &a[i]);
		l[i] = i-1;
		r[i] = i+1;
		q.push((node){a[i], i});
	}
	int tot = n;
	while(!q.empty()) {
		node now = q.top();
		q.pop();
		if(now.val <= 0) break;
		int pos = now.pos;
		if(flg[pos]) continue;
		if(++cnt > k) break;
		ans += now.val;
		a[++tot] = a[l[pos]] + a[r[pos]] - a[pos];
		flg[pos] = flg[r[pos]] = flg[l[pos]] = 1;
		l[tot] = l[l[pos]], r[tot] = r[r[pos]];
		r[l[tot]] = tot;
		l[r[tot]] = tot;
		q.push((node){a[tot], tot});
	} 
	printf("%lld", ans);
	return 0;
}
### 关于信息学奥赛 T1423 种树问题 T1423 是《信息学奥赛一本通》中的经典题目之一,属于贪心算法的应用范畴。该题的核心在于如何通过合理的策略最大化满足条件的数量。 #### 贪心算法概述 贪心算法是一种在每一步选择中都采取当前状态下最优的选择,从而希望最终得到全局最优解的方法。对于种树问题而言,其核心思想是优先考虑能够带来最大收益的位置或顺序[^1]。 #### 解决方案分析 以下是解决此问题的具体方法: 1. **输入处理** 输入数据通常包括街道长度以及若干棵树的种植位置需求。需要先对这些需求按照某种规则进行排序以便后续计算。一般情况下,可以按所需距离从小到大排列,这样有助于逐步填充空间并减少冲突的可能性。 2. **可行性判断与分配** 使用一个布尔数组来标记哪些位置已经被占用。遍历经过排序后的树木需求列表,在每次迭代过程中尝试找到第一个符合条件(即未被其他树占据且间距合适)的位置放置新树,并更新状态标志位表示该处已被利用。 3. **结果统计** 完成上述操作之后,只需简单计数成功安置了多少棵树木即可得出答案。如果实际数量达到目标数目,则说明方案可行;反之则不可行。 ```python def can_plant_trees(n, c, positions): sorted_positions = sorted(positions) count = 1 # First tree planted at position[0] last_position = sorted_positions[0] for i in range(1, n): current_distance = sorted_positions[i] - last_position if current_distance >= c: count += 1 last_position = sorted_positions[i] if count == len(sorted_positions): # Early termination when all trees are placed. break return count # Example usage of the function with hypothetical values n = 5 # Number of possible planting spots c = 2 # Minimum distance between any two adjacent trees positions = [1, 3, 7, 9, 11] # Possible locations to plant trees result = can_plant_trees(n, c, positions) print(result) # Output should reflect maximum number of trees that could be planted under given constraints ``` 以上代码片段展示了基本逻辑框架,其中`can_plant_trees`函数实现了基于排序和间隔检查的关键部分。 #### 复杂度讨论 时间复杂度主要由两方面构成:一是初始阶段对所有潜在植树地点执行快速排序的时间消耗O(NlogN),二是线性扫描整个序列完成验证过程所花费的成本O(N)。因此整体效率较高,适合大规模数据集下的应用场合。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值