首页 > 其他分享 >浅谈一类反悔贪心的问题

浅谈一类反悔贪心的问题

时间:2023-05-09 14:23:44浏览次数:32  
标签:数字 相邻 int LL 反悔 贪心 浅谈

种树

在长度为 \(n\) 的数列中选择至少 \(k\) 个数字,他们都有价值,使得没有相邻的数字被取到,且数字之和最大。

求这个最大的数字之和。

我们考虑一个反悔贪心,首先用一个链表来维护数列,然后,每次贪心的选择最大的数字,并标记左右不可用。

但是这个贪心显然是错的,我们再直接将这三个数字合并为一个,价值为 \(a_L+a_R-a_i\),意思大家应该懂。

显然这个数字,选择它相当于改选 \(a_i\) 两边的数字,这就是我们的反悔了。

再加上一个大根堆维护即可。

需要注意的是,其实这里我们选择的数字不一定是答案方案中的数字,而是我们不断启用反悔机制,不断算上增量,得到最终答案。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
priority_queue<pair<LL,LL> >p;
const LL N=1e6;
LL n,k,a[N],L[N],R[N],len,vis[N],ans;
int main()
{
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		p.push({a[i],i});
		L[i]=i-1,R[i]=i+1;
	} 
	len=n+1;
	for(int i=1;i<=k;i++)
	{
		while(!p.empty()&&vis[p.top().second]==1)p.pop();//无法选的
		if(p.empty()||p.top().first<0)break;//无法选或者选只能变小
		LL t=p.top().second,v=p.top().first;
		ans+=v;
		p.pop();
		LL l=L[t],r=R[t];
		vis[t]=1,vis[l]=1,vis[r]=1;//标记
		a[++len]=a[r]+a[l]-a[t];
		L[len]=L[l],R[len]=R[r],R[L[l]]=len,L[R[r]]=len;//合并处理
		p.push({a[len],len});
	}
	printf("%lld",ans);
} 

种树 2

在长度为 \(n\) 的环中选择至少 \(k\) 个数字,他们都有价值,使得没有相邻的数字被取到,且数字之和最大。

求这个最大的数字之和。

其实当你思考上一个问题的时候,你就会觉得这个链表很有意思,是时候展示链表的含金量了。

我们利用链表的特性,将数组首尾相连即可。

我们只需要添加以下代码:

L[1]=n,R[n]=1;

种树 3

在长度为 \(n\) 的环中强制选择 \(k\) 个数字,他们都有价值,使得没有相邻的数字被取到,且数字之和最大。

求这个最大的数字之和。

如果无解输出 Error!

依然是一个变化不大的题,首先,如何判断无解,根据限定条件,易得:

if(n<2*k)
{
	puts("Error!");
	return 0; 
}

添加至输入后即可。

注意到源代码中有这样一行:

if(p.empty()||p.top().first<0)break;//无法选或者选只能变小

无解已经判定了,这道题强制选择 \(k\) 个,所以删去即可。

核心代码如下:

for(int i=1;i<=k;i++)
{
    while(!p.empty()&&vis[p.top().second]==1)p.pop();
    LL t=p.top().second,v=p.top().first;
    ans+=v;
    p.pop();
    LL l=L[t],r=R[t];
    vis[t]=1,vis[l]=1,vis[r]=1;
    a[++len]=a[r]+a[l]-a[t];
    L[len]=L[l],R[len]=R[r],R[L[l]]=len,L[R[r]]=len;
    p.push({a[len],len});
}

Guard Duty

给定\(n\)个时间点。每个区间都以某两个时间点为左右端点,且每个区间的代价定义为端点的时间之差。

你要选择 \(k\) 个连续的区间,保证这个 \(k\) 个连续的区间没有交集,且代价总和最小。

直觉告诉我们应该从大到小排一个序,然后选相邻的数字,这样代价最小,且这一点显然,在此不证明。

我们用差分处理出相邻的数字形成区间的价值,然后我们发现这里相邻的区间占有相同的点,不可同时选择,也就是相邻的区间不可选择。

那这个反悔贪心就很显然了。

注意这里是最小值,所以你需要搞一个小根堆,而且左右边界要附一个较大的值。

#include<bits/stdc++.h>
#define LL long long
#define T pair<LL,LL>
using namespace std;
priority_queue<T,vector<T>,greater<T> >p;
const LL N=1e6;
LL n,k,a[N],L[N],R[N],len,vis[N],ans;
int main()
{
	scanf("%lld%lld",&k,&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	sort(a+1,a+n+1);
	for(int i=1;i<n;i++)
	{
		a[i]=a[i+1]-a[i]; 
		p.push({a[i],i});
		L[i]=i-1,R[i]=i+1;
	} 
	a[0]=a[n]=1e18;
	len=n;
	for(int i=1;i<=k;i++)
	{
		while(!p.empty()&&vis[p.top().second]==1)p.pop();
		LL t=p.top().second,v=p.top().first;
		ans+=v;
		p.pop();
		LL l=L[t],r=R[t];
		vis[t]=1,vis[l]=1,vis[r]=1;
		a[++len]=a[r]+a[l]-a[t];
		L[len]=L[l],R[len]=R[r],R[L[l]]=len,L[R[r]]=len;
		p.push({a[len],len});
	}
	printf("%lld",ans);
} 

标签:数字,相邻,int,LL,反悔,贪心,浅谈
From: https://www.cnblogs.com/dengduck/p/17384862.html

相关文章

  • 浅谈Ubuntu中的软件包
    1.前言还记得大学第一次接触Ubuntu和Linux的时候,觉得用apt安装想要的软件非常方便。但是有时候出现了问题,各种报错,自己又不懂原理,就会非常抓狂。现在稍微理解一点了,故以较为容易理解的方式记录在这里,方便他人。2.软件包与包管理器dpkgLinux里的软件就是一些可执行文件。就像......
  • 浅谈整除分块
    例题一\[\sum_{i=1}^n\lfloor\fracni\rfloor\\\]首先很容易想到直接求解,对于较大的数据,\(O(n)\)做法无法通过。注意到函数\(y=\lfloor\dfracnx\rfloor\)的图像如下:不难发现,随着\(x\)增大,\(y\)单调不增,这说明对于相同值的\(y\)总是分布在同一块区域。这启发我们根......
  • E. Generate a String(典:贪心+动态规划)
    题目E.GenerateaString题意输入三个不同的整数\(n(1\leqn\leq10^7),x,y(1 ≤ x, y ≤ 10^9)\)。从0开始,每次可以+1,-1,代价是x,或者当前值*2,代价是y问怎样才能到达n用最小的代价思路第一方法是暴力搜索,但是数据过大,不行观察发现,如果从n出发,做所有操......
  • (hdu step 9.1.2)Doing Homework again(贪心——有n份作业,每份作业都有一定的完成时
    题目:DoingHomeworkagainTimeLimit:1000/1000MS(Java/Others)MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):63AcceptedSubmission(s):57 ProblemDescriptionIgnatiushasjustcomebackschoolfromthe30thACM/ICPC.Nowheha......
  • 拼接最大数(栈、贪心)、发奖金问题、二叉搜索树迭代器(栈、树)
    拼接最大数(栈、贪心)给定长度分别为m和n的两个数组,其元素由0-9构成,表示两个自然数各位上的数字。现在从这两个数组中选出k(k<=m+n)个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。求满足该条件的最大数。结果返回一个表示该最大......
  • 浅谈联网汽车安全漏洞
    ​“智能网联汽车存在内生共性问题,即软硬件的漏洞后门,基于此进行的网络攻击可以直接带来勒索、盗窃、大规模车辆恶意操控风险,还有数据泄露等网络安全事件。如果内生的漏洞后门问题不解决,系统自身难保,很难谈系统安全之上的数据安全、应用安全。”——中国工程院院士邬江兴随着汽......
  • 浅谈Protocol Buffers、GRPC、Buf、GRPC-Gateway
    1.ProtocolBuffers什么是proto?ProtocolBuffers如何理解ProtocolBuffers?协议缓冲区非proto协议如何订立、传播以及维护?如何理解协议缓冲区?Protocolbuffers提供了一种语言中立、平台中立、可扩展的机制,用于以向前兼容和向后兼容的方式序列化结构化数据。它......
  • 浅谈(0,eval)('window')
    浅谈(0,eval)('window')最近研究qiankun源码,在import-html-entry包中看到这个,一脸懵,研究了一下,记录一下。参考了这篇博客这个干啥用的 //通过这种方式获取全局window,因为script也是在全局作用域下运行的,所以我们通过window.proxy绑定时也必须确保绑定到全局window上......
  • LeetCode 周赛 343(2023/04/30)结合「下一个排列」的贪心构造问题
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。大家好,我是小彭。今天是五一假期的第二天,打周赛的人数比前一天的双周赛多了,难道大家都只玩一天吗?这场周赛是LeetCode第343场单周赛,如果不考虑第一题摆烂的翻译,整体题目质量还是很不错哒。往期回顾:L......
  • 浅谈C#中动态类型与值类型装拆箱问题
    C#中的值类型封箱、开箱与动态类型的关系封箱和开箱是C#中两个重要的概念,它们涉及到值类型和引用类型在编译七和运行时的处理方式。动态类型是C#4.0引入的一个新特性,它允许在编译时不指定类型,而在运行时动态绑定类型。本文将简要介绍封箱、开箱和动态类型的概念,以及装拆箱与动态......