cf 940E Cashback

本文解析了一道比赛题目,并详细介绍了如何通过观察和逻辑推理找到最优解的方法。利用动态规划(DP)来解决该问题,通过维护一个单调队列以达到线性时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

考场上能想出这道题挺爽得,还剩4分钟的时候A了,copyhls 的B的代码只改了一点点变量头文件和return 0竟然没被判重,结果是long long+=int*int,后面的会变成负数的问题。

思考过程:

看到数据范围是1e5 要么nlogn要么On,nlogn一般是dp+二分维护/线段树等数据结构维护,On一般是贪心或者dp(单调队列,单调栈优化)

首先想贪心的想法,这题就是要找一种划分方式使得能删去的数字的总和最大,那么我们观察第二个样例想到如果把一大堆大的数字放在一起的话,就可以删掉一些比较大的数字,因为他删除的是这个划分区间中最小的几个数字,所以最好是把较大的数字放在一个区间里。

然而贪心好像还是不知道怎么去划分,接着我们想,既然是删掉k/c个,那么k<c是不删除的无意义,k=c删除1个,c<=k<2c还是删除1个,那么相当于第c+1个到第k个放在上一区间是无意义的。证明:假如前c个的最小值是mini ,如果a[c+1]<mini,那么删掉的就是a[c+1],不值得,如果a[c+1]>=mini,那么删除的还是mini,吧c+1个划分到上个区间也是无意义的。

但如果长度为2c的话就能删除2个,但一定不如化成2个c长度的区间优秀。假如前c个的最小值是mini1,次小值是mini2,后c个的最小值是mini3,假如mini2<mini3,那么删除mini1+mini3>mini1+mini2,划分成2段更好,如果mini2>=mini3,那么删除的还是mini1+mini3,是等价的。

这样我们就能想到dp了,f[i]为到i位置能减去的最大的和是多少,可以从f[i-1]转移过来,就相当于把i分到一个长度不到c的区间里,无法减去值,也可以从f[i-c]转移过来,说明吧i-c+1到i分成一个长度为c的区间,然后删掉里面的最小值,用单调队列维护最小值即可。

 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 100010

using namespace std;

int n,c,l,r;
int a[maxl],num[maxl],ind[maxl];
long long f[maxl];
long long sum=0;

int main()
{
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),sum+=a[i];
	l=1;r=0;int pre;
	for(int i=1;i<=n;i++)
	{
		while(num[r]>a[i] && r>0)
			r--;
		ind[++r]=i;num[r]=a[i];
		if(r<l)
			l=r;
		pre=max(0,i-c);
		if(ind[l]<=pre)
			l++;
		if(pre==i-c)
			f[i]=max(f[pre]+num[l],f[i-1]);
		else
			f[i]=f[i-1];
	}
	printf("%I64d",sum-f[n]);
	return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值