洛谷 P1484 种树 贪心+堆+双向链表

本文探讨了一种在给定数值序列中选取至多k个不相邻数以最大化总和的高效算法。通过对最大值的迭代选择与合并,利用优先队列与双向链表优化删除过程,实现O(klogn)的时间复杂度。

本题其实是在nnn个数中选出至多kkk个数,且两两不相邻,并使所选数的和最大。

很容易想到动规思路:f[i][j]表示种到第i棵树且种了j棵的最大获利,则f[i][j]=max(f[i−1][j],f[i−2][j−1]+a[i])f[i][j]=max(f[i-1][j],f[i-2][j-1]+a[i])f[i][j]=max(f[i1][j],f[i2][j1]+a[i]),注意边界、初始化即可。

但是,对于本题n<=300000n<=300000n<=300000的数据规模,动规显然不足以通过本题,需要另想算法。

我们先进行小规模枚举:

k=1k=1k=1时,显然取n个数中取最大的即可(暂不考虑全负的情况)。设最大的数是a[i]a[i]a[i]

k=2k=2k=2时,则有两种可能:1、另取一个与a[i]a[i]a[i]不相邻的a[j]a[j]a[j]。2、取a[i−1]a[i-1]a[i1]a[i+1]a[i+1]a[i+1]

我们可以发现:如果k=1k=1k=1时最优解为a[i]a[i]a[i],那么我们便可以把a[i−1]a[i-1]a[i1]a[i+1]a[i+1]a[i+1]进行合并,因为它们要么同时被选,要么同时落选(证明不难,请自行解决)。而且,我们还注意到:当选了a[i−1]a[i-1]a[i1]a[i+1]a[i+1]a[i+1]时,获利便增加了a[i−1]+a[i+1]−a[i]a[i-1]+a[i+1]-a[i]a[i1]+a[i+1]a[i]。所以当a[i]a[i]a[i]被选时,我们就可以删去a[i−1]a[i-1]a[i1]a[i+1]a[i+1]a[i+1],并把a[i]a[i]a[i]改成a[i−1]+a[i+1]−a[i]a[i-1]+a[i+1]-a[i]a[i1]+a[i+1]a[i],重新找最大的。

每次找的都是最大的数,我们便可以使用堆进行操作,直到堆中最大值小于000或取出kkk个数后停止。复杂度O(klogn)O(klogn)O(klogn)

怎么删去a[i−1]a[i-1]a[i1]a[i+1]a[i+1]a[i+1]呢?这里我们使用双向链表的方式来记录每一块begin−1begin-1begin1end+1end+1end+1。再开一个vis[i]vis[i]vis[i]数组记录它是否被删去,如果被删去的元素出现在堆顶,直接弹出即可。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;

const int N = 500000 + 3;

struct HN {
	LL v; int a;
	HN(LL v,int a):v(v),a(a){}
	bool operator < (const HN& rhs) const {
		return v < rhs.v;
	}
};
int n,m;
int l[N],r[N],vis[N];
LL ans = 0;
LL a[N];
priority_queue<HN> q;

int main() {
	ans = 0LL;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) {
		scanf("%lld",&a[i]); q.push(HN(a[i],i));
		l[i] = i-1; r[i] = i+1; vis[i] = 0;
	}
	r[0] = 1; l[n+1] = n;
	while(m--) {
		while(vis[q.top().a]) q.pop();
		HN s = q.top(); q.pop();
		if(s.v < 0) break;
		ans += s.v;
		a[s.a] = a[l[s.a]] + a[r[s.a]] - a[s.a];
		vis[l[s.a]] = vis[r[s.a]] = true; a[l[s.a]] = a[r[s.a]] = 0;
		l[s.a] = l[l[s.a]]; r[l[s.a]] = s.a;
		r[s.a] = r[r[s.a]]; l[r[s.a]] = s.a;
		q.push(HN(a[s.a],s.a));
	}
	printf("%lld\n",ans);
	return 0;
}
基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
### 洛谷 P3613 链表题解 洛谷 P3613 是一道关于链表操作的题目题目要求实现链表的基本功能,并根据输入数据动态构建链表结构。题目中需要将输入的节点插入到链表的结尾,并在输入结束时完成链表的构建。 #### 题目分析 1. **链表构建**: - 题目要求动态构建链表,输入数据直到遇到 `-1` 为止。 - 每个节点包含一个整数 `data` 和一个指向下一个节点的指针 `next`。 - 使用指针 `head` 表示链表的头节点,`r` 表示当前链表的尾节点。 2. **输入输出**: - 输入的数据通过 `cin` 读取,直到输入 `-1` 为止。 - 每次读取一个整数,并将其插入到链表的末尾。 #### 解题思路 1. **定义链表节点结构**: - 使用 `struct Node` 定义链表节点,包含 `data` 和 `next`。 2. **初始化链表**: - 创建头节点 `head`,并将其作为链表的起始点。 3. **插入节点**: - 使用指针 `r` 跟踪链表的末尾节点。 - 每次读取一个整数后,创建新节点并将其插入到链表的末尾。 4. **结束条件**: - 当输入 `-1` 时,结束链表的构建。 #### 代码实现 ```cpp #include <bits/stdc++.h> using namespace std; struct Node { int data; Node *next; }; Node *head, *p, *r; int x; int main() { cin >> x; head = new Node; r = head; while (x != -1) { p = new Node; p->data = x; p->next = NULL; r->next = p; r = p; cin >> x; } return 0; } ``` #### 代码说明 - **链表节点定义**:`struct Node` 定义了链表节点的结构,包含一个整数 `data` 和一个指向下一个节点的指针 `next`。 - **主函数逻辑**: - 输入第一个整数 `x`,并创建链表的头节点 `head`。 - 使用 `while` 循环持续读取输入,直到遇到 `-1`。 - 每次读取一个整数后,创建新节点并将其插入到链表的末尾。 - 最后返回 `0` 表示程序正常结束。 #### 优化与扩展 1. **内存释放**: - 在实际应用中,链表操作完成后应释放所有动态分配的内存,避免内存泄漏。 2. **错误处理**: - 可以增加对输入的合法性检查,例如处理非整数输入。 3. **功能扩展**: - 可以扩展链表的功能,例如实现链表的遍历、查找、删除等操作。 #### 注意事项 - **输入结束条件**:题目中约定输入以 `-1` 结束,因此在代码中需要明确处理该条件。 - **指针管理**:注意链表指针的更新,确保每次插入新节点时,尾指针 `r` 正确指向链表的末尾节点。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值