首页 > 其他分享 >CF1707B题解

CF1707B题解

时间:2022-10-05 19:12:21浏览次数:80  
标签:cnt 题解 复杂度 差分 CF1707B 序列 前导 include

原题

CF1707B Difference Array


思路概述

题意分析

给定一个长度为 \(n\) 的序列 \(\{a\}\)。每次执行以下操作

对序列 \(\{a\}\) 进行差分,得到差分序列 \(b_i=a_{i+1}-a_i(1≤i<n)\)。

将差分序列 \(\{b\}\) 进行升序排序。

将差分序列中的数值按顺序赋回原序列。

求 \((n-1)\) 次操作后最后剩下的数字

思路分析

先考虑暴力模拟,则时间开销 \(O(n)\) 的差分与时间开销 \(O(n\log n)\) 的排序需要进行 \(n\) 次,总时间复杂度 \(O(n^2\log n)\)。明显超时。

手动模拟几组数据不难发现,对于出现的绝大部分序列,在差分、排序、赋值的过程中总会在最后出现一串 \(0\)。通过进一步分析与模拟可以发现,去除出现的绝大部分 \(0\) 不会影响最后的结果,反而可以节省若干次计算。

考虑每次差分后将序列中的 \(0\) 去除后再排序,可以将时间复杂度降至题目要求范围内。


算法实现

关于时间复杂度的证明

我们先列出一组差分序列全为 \(0\) 的序列,即序列的所有元素都相等。例如以下序列:

\[\{1,1,1,1,1,1\} \]

通过简单数学分析可以知道,该数列在上一次操作前必定是一阶等差数列(为方便表述,笔者称其为逆操作),且元素数量比上述数列多 \(1\)。如下:

\[\{1,2,3,4,5,6,7\} \]

以此类推,可以知道再上一次操作前的序列必定是二阶等差数列。即对初始序列 \(\{1,1,1,1,1,1\}\) 进行 \(n\) 次逆操作后得到的原始序列是 \(n\) 阶等差数列。

通过不完全归纳可以得到基于以上序列推出的 \(n\) 阶等差数列第 \(n\) 项为 \(2^n\)。相应地,对于长度为最大数为 \(2^n\) 的 \(n\) 阶等差数列,只需要 \(n\) 次操作,就可以将其变为 \(1\)。这就确立了最终时间复杂度与 \(\log \max\{a_i\}\) 的关系。

根据题目给出 \(0≤a_i≤5×10^5\) 的数据范围可以知道,即使是最大的 \(a_i\) ,在去除前导 \(0\) 的情况下,也可以理论时间复杂度 \(O(n\log(n+\max\{a_i\})\) 下通过数据点。

关于前导 \(0\)

对于前导 \(0\),如果全部去除,则必然出现问题。例如以下数据:

\[\{0,0,0,7,9\} \]

手动模拟结果为 \(1\),但若去除所有前导 \(0\),结果则为 \(2\)。

若保留一个前导 \(0\),结果为 \(5\),仍然与模拟结果不符。

由上述样例的分析可知,若序列中存在一串长度为 \(m\) 的由非零数组成的子序列,其前方有 \(k(k≥m)\) 个前导 \(0\),则其中的 \(m\) 个前导 \(0\) 对差分都是有贡献的。所以对于这些前导 \(0\) 的贡献,需要用一个变量来记录。而对于一个前面存在有贡献前导 \(0\) 的非零子序列,则在赋值时在差分序列中预置原序列第一个数,就可以在下次差分前插入前导 \(0\)。


AC code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<ctime>
#define RI register int
#define RB register bool
using namespace std;
const int maxn=1e5+10;
int T,n,cnt;
int a[maxn],b[maxn];
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	for(cin >> T,cnt=0;T;--T,cnt=0)
	{
		cin >> n;
		for(RI i=1;i<=n;++i) 
		{
			cin >> a[i];
			if(!a[i])
			{
				++cnt;
				--i;--n;
			}
		}
		for(RI pos=0;n>1;pos=0)
		{
			if(cnt) 
			{
				b[++pos]=a[1];
				--cnt;
			}
			for(RI i=1;i<n;++i)
				if(a[i+1]-a[i]) b[++pos]=a[i+1]-a[i];
				else ++cnt; 
			n=pos;sort(b+1,b+n+1);
			for(RI i=1;i<=n;++i) a[i]=b[i];
		}
		printf("%d\n",a[n]);	
	} 
	return 0;
}

标签:cnt,题解,复杂度,差分,CF1707B,序列,前导,include
From: https://www.cnblogs.com/frkblog/p/16756155.html

相关文章

  • 题解【CF1149C Tree Generator】
    CF1149CTreeGenerator™不一定更好的阅读体验。牛逼题&ZROIDay3数据结构选讲。来一波详细的题解。当时和\(\texttt{ys}\),\(\texttt{hy}\)还有小猴子讨论了半......
  • [题解]洛谷 P4700
    经典题没做出来,是不是该死?是不是该死?首先缩点什么的都是套路性的,然后发现一个事,你要是缩完点直接做,就相当于有向无玕图上标记一些点,求另一些点能到达多少个标记点,这个似乎......
  • CSP-S 模拟赛 #2 题解
    300rk3。题面是本校OJ的,链接挂了找我。upd:T1被xiaopanda的hack数据卡了。T1-A-BProblem出题是一件痛苦的事情!题目看多了也有审美疲劳,于是我舍弃了大家所熟......
  • texlive编译中发现字体有问题解决
    这里可以用tlmgrinfo命令搜索需要下载的字体并从CTAN官网下载。一般这个时候也会有对应的路径,比如texmf-dist/fonts/。把下载的字体解压放在这些路径下,然后分别运行mktexl......
  • 【LGR-122】T1 & T2 题解
    T1下面所说的做法来自于dty(%%%%%%%%%)注意到每一个数的绝对值是大于等于\(2\)的,那么就可以发现一个性质:当一个区间长度为\(len\)时,如果\(len\ge62\),那么这个区间的......
  • 组态软件报警问题解决
    作为工业自动化领域的从业者,经常会使用各种组态软件,近期作者在使用业界鼎鼎大名的组态软件IFix过程中就遇到了一个小case,现在分享给大家。众所周知,IFix在运行过程中报警会......
  • 【题解】P3583 [POI2015] KWA
    模拟赛出这道题???还好赛时乱搞做出来了(/hanxlinkDescription定义一个数\(n\)的拆分为:将\(n\)表示为若干个不同的正整数的平方和。令\(k(n)\)为\(n\)的拆分中最......
  • CF 547D. Mike and Fish 题解
    Solution1二分图染色显然这题是构造染色方案,于是我们考虑将矩阵转化成图进行染色。结论:将同一行的点两两配对,将同一列的点两两配对,形成的一定是二分图。证明:由于每......
  • P4572 题解
    前言题目传送门!更好的阅读体验?双倍经验:P3554(数据坑一点)。简要题意可以看P3554。思路:二分答案+树形DP。思路答案显然具有单调性,所以考虑二分答案。\(\operatorna......
  • P3226 [HNOI2012]集合选数 题解
    纪念一下30紫and500AC首先先膜拜一下神仙出题人,这题太神仙了。题意:要构造一个集合,使得$x\inA$,满足$2x\notinA$且$3x\notinA$,求\(\{1,2,\ldots,n\}\)......