首页 > 其他分享 >cf 1852C

cf 1852C

时间:2024-03-21 16:11:35浏览次数:21  
标签:这个 1852C 决策 cf 反悔 答案 dp 贪心

链接

\[f[i][j]表示前i个数字,然后最后一个数字是a[i]+k\times j个区间的结尾,干掉所有章鱼的最小代价 \]

这个是我最开始想的dp的状态。然后很明显\(j\)是可以挺大的,但是如果你不去证明而是感性理解(瞎猜)的话,就很有可能得到\(j\in[0,1]\)的结论。然后用这个写出来一个\(O(n)\)的dp,快乐的wa在test5
(别问我怎么知道的)
事实上,j是可以很大的,大到\(n/2*k\)的级别。
具体的构造方法就是,构造一个多峰的序列,其中从中间往两边谷底大小逐渐上升,中间最低。

但是我的理性告诉我,前后两个数字之间一定是有一些联系的。

从头开始分析吧。
对于这种区间覆盖的操作,还是很熟悉的。需要的总操作数就是最终高度的差分数组的所有的正值的和。
抽象一下,我们的目标就是对每个数字进行+k,来使得这个总操作数最小。
那我们就考虑一下,对于一个确定的数组,我们进行什么样的操作,能使得答案变优秀
先下点定义。如果一个位置的差分数组是正数,我们就称其为一次上升(ascent),如果为负数,就称其为下降(descent)
显然,上升是会使得答案增加的,而下降则是不会对答案产生影响
下降不产生影响,其实就是边界处的章鱼总是不会重生,因为它重生是一定不会让答案变优秀的。
这是可以显然得到的结论。
所以,需要通过对\(a[i]\)来加上一些\(k\)构造的数组,开头和结尾一定是不会被加上k的。
其实我们要使用的结论和这个是有一定的相似性的。这个结论应该是和这个区间覆盖和这个+k的操作强相关。
因为它产生的原因是这个区间覆盖的答案统计的特性,和这个+k操作的特性。就是下面的引理部分。

设\(b[i]=a[i]\mod k\),
假设我们求解到的最优的答案是\(c[i]\),就是对\(a[i]\)加上数个或者零个\(k\)得到的数组
我们的最优选择策略就是,每当我们能够让\(c[i]\)选择小的情况的时候,让他选择小的情况。
如果无法选择变小的情况,就找到前面(这里也可以)可以变大,并且代价最小的部分,使用这次变大的机会,然后让这里变小。

引理
对于答案\(c[i]\),假如\(c[i+1]-c[k]>k\),那我直接让\(c[i+1]-k\),是肯定不会让答案更劣的。
这是显而易见的,一共就两种情况,一种是,后面的\(c[i+2]>c[i+1]\),那\(c[i+1]\)变化后,明显答案不变
第二种,\(c[i+2]\leq c[i+1]\),那变化后答案甚至更优秀了
综上,答案不会更劣。

那么对于每个位置,可供选择的数字一共就两个,如果\(a[i]\mod k = a[i-1]\mod k\),那甚至就只有一个情况。
很明显,对于最后的答案,我们是要求尽可能小的,所以对于每个位置,我们都优先选择其中更小的情况,因为这样不需要先给答案加上代价。
假如这次无法选择更小的也就是不得不让答案变得更大,那最优的也是挑选前面的一次没有选择过的且使答案增加最少的位置来增加我们这次需要的k,让这次不需要再付出代价。因为在前面付出代价和在这里付出代价产生的效果是等价的,那肯定是选择代价最小的一次。

这个操作和我的dp很像,区别在于一个是相对的+k,而一个是绝对的+k。
我想不到的原因,我感觉在于我对这个区间覆盖的答案统计的方式不够熟悉。
让我想我肯定是能想到的,但是就是因为不够熟悉,所以在对他使用的使用的时候就不能很灵活了。
而且这个反悔贪心确实是能用巧妙来形容。可能我知道了需要用的引理,也不会去写这个反悔贪心,而是会写图论类似的东西。
虽然最短路也是\(O(nlogn)\),但是这个题解的代码确实是简洁而优美的。

思路应该是要逐渐往后的,就是从\(a[1]\)开始,往后想,要怎么让\(a[i+1]\)的位置变化才能求到更优的答案。这样每一个位置相对上个位置只能有两个选择的引理就很好看出来了。
然后就是下降优先的分析。
其实这个很好做,因为我每次下降不付出代价,而上升则是要付出代价,那自然是贪心的取,答案会更小。
但是如何证明正确呢?
这个就是反悔贪心了。
首先,如果答案原始是最优秀的,我们要证明证明,用这种贪心生成的下一步的答案依旧是优秀的?
很明显啊。如果这里能继续下降,那自然是下降更优秀。如果不能,那最优的也是挑选前面的一次没有选择过的且使答案增加最少的位置来增加我们这次需要的k,让这次不需要再付出代价。很明显,没有更优秀的选择。
那从1开始,只有一个数字的时候,自然是不加k的时候最优秀。
数学归纳法,证明了。

但是为什么我还是觉得有地方不够清晰?
或者说,让我再独立的思考一遍这个过程, 我会不会还有地方是依靠记忆而不是自然的思考?
1.从左往右,考虑如何构造一个答案最小的答案。
2.通过上面发现引理,但是我要怎么样才能通过引理来想到这反悔贪心的做法?
对于我来说,图论的做法更自然。
但是这个始终向下的贪心,是不在我自然思考的范围内的。
把他加进去。
以后的事情,可以以后再反悔。
很奇妙,真的,这就像一个后效性十分确定的dp一样。我前面的每一个决策产生的后效性都是确定的,以至于我可以在后面操控前面的决策改变的同时利用后效性的变化。
第一次写到,这个上升下降的模型,可以记一下。留个印象。

如果这个后效性的想法能在脑力子里面成型,那就可以想到这个优先队列的想法。
也就是,我们要注意到“改变决策产生的影响是可预测的”这一点。如何再配上题目的特性,就可以产生这样的一个反悔贪心
好好好,我现场出一个试试看。

首先,决策是否可多重?
不可以吗?
因为所有的决策都再优先队列中。如果一个点有了多个决策,要么它这多个决策之间产生的影响都能是一样的,要么,对于每点的决策数量就都是固定的,而且保证每次使用后,这个决策点无法再被使用,否则会TLE。但是这个要求其实可实质化为一个性质,既然我每次只能选两个决策点,一个先用着,一个放队列,那其他的我用它干什么呢?如果我不能及时的判断出他们是否会被最终答案使用上,那我能不能判断出最优秀的,就是优先使用的答案是谁呢?

如果我能,为什么我不能判断出剩下的呢?

这个可以用限制保证。假如我这次下降所需的不再是一次上升所能满足的,那我就需要用到区间查询了,是动态的在线区间查询。
用值域线段树可以做到吧。而且需要能够支持删除操作。这个还好。
这样设计的题目,很强硬。而这题,很自然。
这个是我做不到的,也是我觉得这题好的原因。

可以出一个很有意思的dp,这个dp的决策没有及时性,也不需要数组来存放,我们也可以叫他,反悔贪心。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
	char c=getchar();int a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int n,k,a[200001];
int f[200001][5];
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int T=read();
	while(T--)
	{
		n=read(),k=read();
		priority_queue<int,vector<int>,greater<int> >q;
		ll previous=0,x,ans=0;
		for(int i=1;i<=n;i++)
		{
			x=read();x%=k;
			if(x>previous)
			{
				q.push(x-previous);
				ans+=q.top();
				q.pop();
			}
			else
			{
				q.push(k+x-previous);
			}
			previous=x;
		}
		cout<<ans<<endl;
	}
	return 0;
}

标签:这个,1852C,决策,cf,反悔,答案,dp,贪心
From: https://www.cnblogs.com/HLZZPawa/p/18087607

相关文章

  • CF1945E Binary Search 题解
    CF1945EBinarySearch题目大意给定一个\(1\simn\)的排列\(A\)(不保证有序),对这个排列用如下代码片段二分,查找\(m\)的位置。intl=1,r=n+1;while(r-l>1){intmid=(l+r)/2;if(A[mid]<=m) l=mid;else r=mid;}cout<<l;显然不一定能查找到正确位置,所以在......
  • CF938E-组合数
    link:https://codeforces.com/contest/938/problem/E题意:给一个序列\(a\),按如下方式计算\(f_a\):初始\(f_a=0,M=1\)对每个\(2\leqi\leqn\),如果\(a_M<a_i\),\(f_a\tof_a+a_M\),然后\(M=i\)对所有\(a\)的排列计算\(f_a\)并其在模\(10^9+7\)下的和。\(1\leqn\leq......
  • Windows7系统icfupgd.dll文件丢失问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个icfupgd.dll文件(挑选合适的版本文件)把它放......
  • CF817F MEX Queries 题解
    题目链接:CF或者洛谷不是很难的题,但在这里提供一个动态开点线段树怎么卡空间卡过去的极致空间处理技巧全局\(mex\)问题,常见的做法就是维护权值树,然后找第一个没有权值的点,可以维护\(\min\),但本题存在第三个操作,所以不能再去传统地维护\(\min或者\max\)去辅助二分了。观......
  • CF765F,CF1793F,JSOI2009:区间最接近的两数
    link:https://codeforces.com/contest/765/problem/F据说是典中典问题(出现三次了)题意:给一个序列\(a_1,\dots,a_n\),有\(m\)次询问,每次询问给\(l,r(1\leql<r\leqn)\)问\(\min_{l\leqs<t\leqr}|a_s-a_t|\)\(1\leqn,m\leq10^5,a_i\leq10^9\).思路这个做法还是很妙,想......
  • CF1091F 题解
    blog。提供线性做法,各方面完爆反悔贪心。先钦定能不飞就不飞,最后再分配盈余的能量。可能会在飞Lava的时候不够能量,只需要在前面来回移动,刷能量即可。由于Swim比Walk快,所以能Swim就全部用Swim刷能量,不能就Walk。最后是分配盈余能量。显然优先把Walk换成Fly,换一......
  • CF1945 H GCD is Greater
    CF1945HGCDisGreater什么鬼啊div3Hdiff:2775。纯属码力题。首先发现\(\gcd\)肯定数字越多越小。然后与值数字越多越小。所以结论就是选择两个数字取\(\gcd\),剩下的数字分到另一个集合。那么问题就变成了找出一对数字,它们的\(\gcd\)和剩下的数字的与做差值最大......
  • CF1139E Maximize Mex
    传送门题意:在一所学校里有\(n\)名学生和\(m\)个社团,社团被编号为\(1\)~\(m\)。第\(i\)个学生有一个能力值\(p_i\),且属于社团\(c_i\)(每个学生恰好属于一个社团)。学校将要举行一个为期\(d\)天的活动,每天学校要举行一场程序设计比赛——校长将会从每个社团中各选......
  • CF639E - Bear and Paradox | 二分答案 思维
    links题目大意自己可以想出来个七七八八,但很多地方没有把细节处理好,思考问题不全面,然后就花了很长时间……显然答案具有单调性,直接二分答案。对于一个二分的答案\(c\),思考如何找到最优的做题顺序,考虑相邻的两道题,把他们的顺序调换,看最终的得分会如何变化。因为把这两道题调......
  • CF1935 A-C题解
    A设\(s\)翻转后的字符串为\(t\),考虑进行\(n\)次操作可能生成出哪些字符串:只进行翻转操作——\(s\);先复制再\(n-1\)次翻转——\(s+t\);先翻转,再复制,再翻转\(n-2\)次,\(t+s\);多次复制的情况。情况2显然劣于情况1;情况4得到的字符串的开头一定是\(s\)或者\(t\)......