题解 Codeforces Round 885 (Div. 2) / CF1848A~F

https://codeforces.com/contest/1848/

VP 选手 前来报到

A. Vika and Her Friends

https://codeforces.com/problemset/problem/1848/A

Problem

一个 n×m 的网格。Vika 和她的朋友们在格子里,他们互相知道彼此的位置。每秒钟,Vika 先移动到相邻格子,朋友在知道 Vika 的位置后也分别移动到相邻格子里,这样以后,Vika 如果与朋友格子重叠,则 Vika 被抓住。Vika 永远都不会被朋友抓住吗?

Solution

考虑 Vika 和其中一个朋友的曼哈顿距离:Vika 走一步,他们的距离要么加一要么减一;朋友也一样。那么每秒后他们的距离,要么不变,要么 ±2。那么与 Vika 距离为奇数的朋友,永远抓不到 Vika。与 Vika 距离为偶数的朋友,总能将 Vika 逼到角落将其击杀。

B. Vika and the Bridge

https://codeforces.com/problemset/problem/1848/B

Problem

长为 n 的木板上染满颜色。你可以再更改一个区域的颜色。然后选择一些颜色相同的区域,使得他们两两间的距离最大值最小(包括两个边界)。n105

Solution

每种颜色分开讨论。间隔最远的区域,在中间染一次颜色。

C. Vika and Price Tags

https://codeforces.com/problemset/problem/1848/C

Problem

长为 n 的数列 a,b。每秒钟进行这样一次操作:

  • 构造 c 使得 ci=|aibi|
  • a:=b,b:=c

是否存在一个时刻使得 a 全为 0?非负整数数列 ai,bi109n105

Solution

每一位分开讨论。观察到如果有零,则变化将形如 0,a,a,0,a,a,,以三为一个循环,这启发我们。另一个启发点在于这个减操作和 gcd 过程很像,所以最后这个重复的 a 其实是 gcd

那么我们尝试优化这个 gcd 的过程。

int solve(int x,int y){//最终的 0 出现在哪里
	if(!x) return 0;
	if(!y) return 1;
	if(x<=y) return solve(y,y-x)+1;//+1 表示位移一下,对上最终的循环
	return solve(y,x-y)+1;
}

现在 x>y。回想更经常的求 gcd 的方法,应该是 gcd(x,y)=gcd(y,xmody),这启发我们用模运算优化最后一步。大概写一下这个数列:

x,y,xy,{x2y,y(x2y)2yx,(x<2y)

那么可以大概发现就是说减掉奇数个和偶数个 y 是不一样的,对它小小分讨一下。

int t=x%y,d=x/y;
if(d%2==0) return solve(t,y);
else return solve(y,t)+1;

最后想使得整个数组都是 0,必须保证它们最终的循环节叠在一起。0,0 开局的请丢掉。

D. Vika and Bonuses

https://codeforces.com/problemset/problem/1848/D

Problem

有计数器 s0,输入给定初值。执行以下二选一个操作,重复 k 次:

  • s:=s+(smod10)
  • 获得 s 的收益。

使得收益总和最大化。s,k109

Solution

发现 s:=s+(smod10) 这个操作,如果只看 smod10(就是个位),那么它有循环节。不妨拎出单独考虑。

其中 2,4,8,6 明显是环,1,3,7,9 能一步到环,5,0 是孤独的。

另外一个观察是:我们总会先做操作一再做操作二。于是分类讨论:

  • 全部都是收益。
  • 用一个操作一,然后全部都是收益。5,0 到这里可以停止。

剩下的可以走好多次,我也说不好怎么样更优。因为环的长度为 4,我们按模四分类:

  • 进入环后,用 4x 次操作一,剩下的全点操作二。
  • 进入环后,用 4x+1 次操作一,剩下的全点操作二。
  • 进入环后,用 4x+2 次操作一,剩下的全点操作二。
  • 进入环后,用 4x+3 次操作一,剩下的全点操作二。

我们可以就是在外面动态维护当前可以用的操作次数 k,在进入环的基础上,先跑一遍,然后 k 减一,s:=s+(smod10),又跑一遍,重复共四次。这样明显可以。

那么怎么求最大值?考虑将答案写出来:(这个 k 被改过了,理论上来说应该加角标的,但我不管)

ans=(k4x)(s+20x)=80x2+(20k4s)x+ks,where 04xk

开口向下的二次函数,激动人心的求导时刻。那么我们对它求导,找出导数的零点(也就是 b2a)即最大值取值 x0,取 x0 附近的几个答案和 f(0),f(k/4),注意定义域。

E. Vika and Stone Skipping

https://codeforces.com/problemset/problem/1848/E

Problem

给定 X。有多少个正整数对 (x,y) 使得 xyi=xy=X?询问好多次,先给一个 X0109,然后告诉你 XiXi1(小于 106 的正整数),对所有 Xi 分别求出答案,还有对质数取模。

Solution

不妨先将 X 翻倍,去掉求和公式里面一个很烦的 12

2i=xy=2i=1y2i=1x1=y(y+1)x(x1)=y2+yx2+x=(x+y)(yx+1)=2X.

这启发我们对 2X 分解因数。观察到:(x+y)+(xy+1)=2x+1 是个奇数,这要求我们的这一对因数的和要是奇数。而且一对因数唯一对应一个 (x,y)

我们分解的竟然是 2X,不妨把所有 2 放在一边,选择一些奇数质因子放在另一边。那么我们终于看出方案数是 x2(cntx+1) 其中 cntx2X 的唯一分解的出现次数。

这个东西怎么维护呢?这个模数可能很小,可能没有逆元。所以用线段树维护。

F. Vika and Wiki

https://codeforces.com/problemset/problem/1848/F

Problem

数列 a 下标从零开始,长度 n=2k220,值域 [0,230)。每秒钟进行一次操作:所有数字同时 ai:=aia(i+1)modn(异或)。求什么时候整个数列清零。我们可以证明方案一定存在。

Solution

先按位拆分手完几个:01010101 可以两步。我们可以考虑做两次操作意味着什么:(o 表示取这些数字的异或和)

0:o
1:oo
2:o o
3:oooo
4:o   o
5:oo  oo
6:o o o o
7:oooooooo

竟然是分形,又因为一个全零的数列再做操作没啥意义,我们想到二分求这个东西。但是我们似乎求不出来某一行。但是我们能求出 2k1 行(取 2k 个数)进一步 2k 也可以(甚至更简单),所以倍增。发现惊人事实:这玩意不用按位处理。同时证明不可能无解:第 n 秒时因为取模,所有数字需要的那两个点重合,所有数字都是零。O(nlogn)代码真的很优美

以下更新:

@Morning_Glory
呃我可能说的不好,大概是说你分析两次操作对应原数列哪些数字异或,三次是哪些,四次是哪些,最后发现它像一个杨辉三角的图形,而且第 2j 行(即 2j 次操作)对应原序列 i,i+2j 两个位置的数字的异或和。又因为一个全零数组再操作也是全零,所以使用倍增算法,快速计算进行 2j 次操作后序列的样子,然后更新一下指针。证明一定有解是注意到 n=2k,当进行 2k 次操作时刚好会因为取模把要用的两个数重叠变成 0,从而变成全零的数组。

这个重要结论也可以通过暴力展开,或者用 2j12j1 归纳证明。

这边 看到一个神奇优化可以线性,就是说搞完一次后数组前后两半是一样的,只用做其中一半就行了。不知道对不对?因为有的倍增点是不用的啊。我不知道。

Codes

posted @   caijianhong  阅读(565)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示