首页 > 其他分享 >CF1661D Progressions Covering 题解

CF1661D Progressions Covering 题解

时间:2023-10-03 22:33:31浏览次数:40  
标签:CF1661D 10 题解 sum Progressions 操作 ll nowadd

最详细的题解

题目传送门:Progressions Covering
阅读前人题解时,限于个人能力有限,有一些地方想了好一会儿才懂。发现很多题解都是在 @SDLTF_凌亭风 等作者基础上延伸,但详细程度依旧有限,尽管这篇题解亦是站在他们基础上延伸的,这篇题解更为详细的点明了很多地方。
本人第一次写题解,讲的不是很通顺,如果看不懂您可以对照着其他作者的题解看,见谅。

思路

  1. 由于数组 \(a\) 刚开始时全是 \(0\),要通过对 \(a\) 数组一定规则的加法操作使得 \(a\) 数组达到 \(a_i\ge b_i\),可以转化为仅操作 \(b\) 数组做相同规则的减法,使得 \(b_i\le0\),如此,我们便不用考虑 \(a\) 数组的问题力。

  2. 由操作规则可知,对于一个 \(b_i\) 我们取其前面尽可能大的区间,可以使得 \(b_i\) 被减少的最多,可以实现次数更少达到 \(b_i\le0\) 的目的。
    因为是取每一个 \(b_i\) 前面的区间,我们贪心的从后往前(从右往左) 扫。

  3. 由于按照要求我们对一个区间进行等差数列的加减操作,我们很自然可以想到二阶差分的做法,例如:
    对于一个区间 \(1-10\) 每个数加 \(10\) 的操作如下(采用一阶差分):
    对于一个区间 \(1-10\) 进行第 \(i\) 个数加 \(i\) 的操作如下(采用二阶差分):
    如果对二阶差分不甚理解,这里有一些经验豆:
    P4231 三步必杀
    P5026 Lycanthropy
    蓝桥杯—绝世武功(此题链接找不到了)

一些具体实现

(这段话比较抽象,可以先看一看程序实现再回来读,如果程序读懂了可以不用再看了。)

  • 如何实现差分?
    我们用一个 \(tot[i]\) 数组来维护 \(b_i\) 对 \(b_{i-1}\) 至 \(b_{i-k+1}\) 的影响,即为了使 \(b_i\) 减掉 \(k\),根据操作规则实际上他左边 \(k-1\) 个数也要按规则减去一定值,我们称其为“ \(b_i\) 对左边数的影响”。
    具体而言,假设 \(k=5,b_{10}=10\),为了使 \(b_{10}\) 减到 \(0\):\(b_{10}\) 要减 \(10\),相应地 \(b_9\) 要减 \(8\),\(b_8\) 要减 \(6\), \(b_7\) 要减 \(4\),\(b_6\) 要减 \(2\);此时,要减的 \(2,4,6,8,10\) 构成一个等差数列,如果令 \(tot[6]=2\) 对 \(tot_i\ (i\in[6,10])\) 做前缀和操作,发现数组变为 \(2,2,2,2,2\)。也就是说 \(tot[i]\) 本质上维护了一个二阶差分的角色,使得当前 \(b_i\) 的影响可以顺利向左施加。
  • 怎么让之前的影响加在当前数?
    利用一个 \(sum\) 维护当前 \(b_i\) 被右侧一面包车数的影响的大小,即如果 \(b_i-sum\le0\) 已经成立,我们对这个数就不用操作了,否则计算要操作的次数并把他对左边接下来的数的影响记录。即 \(sum\) 实现了一阶差分的角色。
  • 怎么记录影响?
    用一个 \(times\) 记录应该对当前数的操作次数。
    用一个 \(newadd\) 记录已经操作次数。
    每次更新 \(sum\) 时,要使 \(sum-nowadd\)。
    重点: 为什么要减?维护一阶差分。
    因为要减的数是一个等差数列,如果对当前数的一个操作减去了 \(x\),那么这个操作对左边这个数减去的是\(x-1\),\(nowadd\)记录了目前正在进行 \(nowadd\) 次操作,左边这个数受右边(之前)数的影响应该是 \(sum-nowadd\),这便巧妙地维护了实际差分的值是等差数列的性质。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 300030
ll orl[maxn]; //b数组,记录原始的值(original)
ll tot[maxn]; //记录操作次数
int n,k;
ll ans; //答案统计
ll sum; //下一个数应该减去多少?(受到了多少影响)
ll nowadd; //当前进行了多少次操作

inline long long read(){
	char readch=getchar(); ll readtmp=0;
	ll readflag=1;
	while(readch<'0' || '9'<readch){if(readch=='-')readflag=-1;readch=getchar();}
	while('0'<=readch && readch<='9'){readtmp=readtmp*10+readch-'0';readch=getchar();}
	return readtmp*readflag;
}

int main(){
	cin>>n>>k;
	for(int i=1; i<=n; i++)
		orl[i]=read();
	
	
	for(int i=n; i>=1; i--){
		int pos=max(1,i-k+1); //可以取到的最大区间的左端点(注意细节每一个操作区间左端最小为0)
		int jian=i-pos+1; //可以取到的最大区间长度,即当前这个orl[i]一次操作最大减多少
		orl[i]-=sum; //之前数对 orl[i]的影响,即之前操作使得orl[i]减去了多少

		ll times=0; //还需操作次数
		if(orl[i]>0)  times=(orl[i]+jian-1)/jian;
		if(times>0){
			ans+=times;
			nowadd+=times;
			sum+=1ll*jian*times;
			tot[pos]+=times;
		}
		sum-=nowadd; //重点。
		nowadd-=tot[i]; /*重点。减的原因是之前操作过期了,注意一个操作有效期只有操作长度k*/
	}
	cout<<ans;

	return 0;
}

标签:CF1661D,10,题解,sum,Progressions,操作,ll,nowadd
From: https://www.cnblogs.com/ChillLee/p/17741747.html

相关文章

  • 洛谷 Power Tree 题解
    题目链接PowerTree分析将叶子节点按dfs序重标号后,每次控制操作可以转化为将子树内叶子节点所在区间加(或减)一个数不难可以想到将叶子区间进行差分每次对\(l\)到\(r\)的操作可以转化为将\(l\)上的数转移到\(r+1\)上每次操作后差分数组的和不变将所有点权变为\(0\)......
  • [题解] CF632F - Swimmers in the Pool
    CF632F-SwimmersinthePool题目传送门题意给定一个大小为\(n\timesn\)的矩阵\(A\)。假设\(A\)满足以下条件,那么称该矩阵为MAGIC,否则为NOTMAGIC,并输出对应的属性(即\(A\)是MAGIC还是NOTMAGIC)。$A_{i,j}=A_{j,i}$;$A_{i,i}=0$;$A_{i,j}\le......
  • GDCPC2023 B , D , F , K 题解
    和队友一起打的2023年广东省大学生程序设计竞赛重现赛,写了B,D,K,胡了一个F。D题目大意随着广东的建设与发展,越来越多人选择来到广东开始新生活。在一片新建的小区,有\(n\)个人要搬进\(m\)栋排成一行的房子,房子的编号从\(1\)到\(m\)(含两端)。房子\(u\)和\(v\)相邻......
  • 题解 [CSP-S 2021] 括号序列
    题目链接对于括号题,基本是栈匹配没有匹配的左括号和区间\(dp\)两个方向。这道题括号序列并不确定,只能用区间\(dp\)搞。如果直接设\(f_{l,r}\)表示\(l\simr\)的合法括号序列,那么由区间\(dp\)的套路可知,需要枚举中间点进行合并,那么\(()()()\)的情况就会出问题,原因是......
  • 【UVA 12100】Printer Queue 题解(队列+优先队列)
    计算机科学学生会中唯一的打印机正经历着极其繁重的工作量。有时,打印机队列中有100个作业,您可能需要等待数小时才能获得一页输出。由于某些作业比其他作业更重要,黑客将军为打印作业队列发明并实现了一个简单的优先级系统。现在,为每个作业分配1到9之间的优先级(9是最高优先级,1是最低......
  • [题解]CF1748C Zero-Sum Prefixes
    UPD23.10.3更新的对思路的描述,以及代码。思路对于每一个\(a_i=0\),如果我们将它变为\(x\),都可以直接将\(i\simn\)位置上的前缀和加\(x\)。设\(a_j\)是\(a_i\)后第一个\(0\),那么,在\(j\)时同样有上述规律。所以,我们只需在\(i\)时考虑,\(i\sim(j-1)\)的贡......
  • 题解 [蓝桥杯 2016 省 B] 交换瓶子
    题目链接本题解讲解环图的做法。要将一个\(1\simn\)的排列通过交换变成\(1\simn\),可以先将\(i\)向\(a_i\)连边,那么最终一定会练成若干个环(每个点只有一个出度,也只有一个入度)。假设交换在同一个环中的节点,一个环显然会变成两个环,也就是说,交换一次最多增加一个环的数量,......
  • 【题解】洛谷 P1003 [NOIP2011 提高组] 铺地毯
    原题链接解题思路如果直接按照题意开一个二维数组来模拟每个点最上面的地毯编号,会发现所占空间最坏情况下约为(2*105)2*4B=4*1010*4B=1.6*1011B≈149GB,程序完全无法运行。但实际上没有必要将每一个点的信息记录下来,只需要记录每一块地毯能覆盖哪些点,再依次判断哪那些地毯可以......
  • 「题解」Codeforces Round 894 (Div. 3)
    A.GiftCarpetProblem题目Sol&Code签到题#include<bits/stdc++.h>#defineN21typedeflonglongll;intmin(inta,intb){returna<b?a:b;}intmax(inta,intb){returna>b?a:b;}intT,n,m,a[4];std::strings[N];i......
  • T2回家(home)题解
    T2回家(home)现在啥也不是了,虽然会了逆元,但是对期望概率题还是一窍不通,赛时相当于只推出了\(n=1\)的情况,结果运用到所有情况,理所应当只有20分。题目描述小Z是个路痴。有一天小Z迷路了,此时小Z到家有NN个单位长度。小Z可以进行若干次行动,每次行动小Z有\(\frac12\)的概率向......