Codeforces Round #879 Div.2

link

前言:VP了一把,rk731,如果赛上有这发挥就好了。

果然,D是分水岭,一直都是。

Unit Array

题面:
给定一个长度为 n(1n100) 的序列 a,所有元素均为 11。我们称 a 是一个好序列,当且仅当同时满足以下两个条件:

  • a1+a2+...+an0
  • a1a2...an=1

你可以对序列进行若干次修改,每次修改可以把序列中的 1 改成 1 或从 1 改成 1

给定一个序列,问最少需要几次修改使它变成一个好的序列。

题解:显然,我们只需要将负数改为正数。设有 c1 个 1,有 c2 个0,则我们需要调整后 c1c2,c2mod2=0

满足第一个条件,需要代价 max(0,c1c22),而第二个条件,在满足第一个条件后再判断是否合法,不合法就再减一个1.

Maximum Strength

题面:

每一种材料的力量由一个十进制整数表示。

对于一个武器,由两种材料构成。假如第一种材料的力量为 X=x1x2xn,第二种材料的力量为 Y=y1y2yn,那么这个武器的力量为 i=1n|xiyi|,也就是 |x1y1|+|x2y2|++|xnyn|

如果两个数字长度不一样,则要将短的数字用前导零补成相同长度

现在,你拥有无数个力量在 [L,R] 中的材料。你想要选出两个材料做出一个力量最大的武器。请你求出你设计出的武器力量的最大值。

题解:

乍一看,毫无思路,但我们显然是尽量让每一位的差变小才对。

对于最高的已经确定的几位,我们直接跳过,然后找到第一个 liri 的。

此时,注意到我们可以划分两个数的上下界,然后下一位令较大数为0,较小数为9,此后的所有位全部可以用0,9两个数交替了。

所以答案为:d+9(ni)

Game with Reversing

题面:

小 L 和小 S 在玩游戏。他们有两个长度均为 n(1n105) 的字符串 S,T,小 L 和小 S 轮流操作,小 L 先手。

小 L 的回合,他可以选择 1n 中的一个整数 i,再选择串 ST,把其中的第 i 个字符改成任意一个字符 c

小 S 的回合,她可以选择 ST,并将它进行翻转。

如果两个串 S,T 经过若干次操作后相等,则游戏立即结束。小 L 希望总操作次数最小,小 S 希望总操作次数最大。两人都采取最优策略,问最终操作次数。

题解:千年难遇的水C题。

注意到,小L可以修改任意字符,他有两个选择:在不翻转的状态下相同,翻转后相同。

这里我们分别计算出 c1=i=1n[siti],c2=i=1n[sitni+1]

对于第一种情况,小 L 至少需要 c1 次操作把字符变成相同的,然后若 c1mod2=1,则小S作的翻转没有意义,答案为 2c11,否则需要小S再翻回来。故最终答案为 2c1(c1mod2)

Survey in Class

题面:

n 个学生同时对课堂内容进行了预习。有 m 个问题,第 i 个人预习的问题是一个区间,可以用 [li,ri] 表示。每当老师问出一个问题,如果一个人不会,它的分数就会 1,否则 +1。注意,分数可能为负。

现在你要问一些不重复的问题,最大化学生分数的极差,并输出这个值。

有意思的问题,不过比较简单。

首先,我们将其放在数轴上,视作线段,则对于选了 c 个点,线段 i 里有 pi 个点,则得分为 pi(cpi)=2pic,而极差 dmax=(2pic)max(2pic)min=2(pmaxpmin)

所以, d 与问了几道题完全没有任何关系。我们只需要求 Δp 的最大值即可。

问题化为:在数轴上选若干个点,使得点最多的线段减去点最少的线段的差最大。

显然,必定存在一种最优方案,点最少的线段里没有点。

证明:当两线段不交时,显然。

当两线段相交时,必定是相交部分的点,而这个点会被做差抵消掉,故无用。

换句话说,我们要求:

dmax=max1i,jn{rili+1f(i,j)}=max1in{rili+1min1jnf(i,j)}

其中 f(i,j) 是两线段相交长度。

处理 f 复杂度太高,考虑优化。我们如果枚举线段 i 则只需要处理与它相交最少的线段。分类讨论:

  1. 不相交:这显然是最好
  2. i 左侧与 j 相交。这样的话,相交线段的右端点自然是越小越好,我们记录所有线段里右端点最小的数,记作 R
  3. i 右侧与 j 相交,类比上一个,相交线段的左端点自然是越大越好,我们记录所有线段里左端点最小的数,记作 L
  4. i 包含 j。这种情况可以直接被处理掉。

我们直接处理最大线段长 mx 和 最小线段长 mn,这种情况下答案绝不会大于 mxmn,可以直接将其计入答案。因为如果最大线段和最小线段是前三种情况,答案会被更新掉

那么,做法显然:

int main(){
	ios::sync_with_stdio(false);
	read(t);
	while(t--){
		read(n);read(m);
		for(int i=1;i<=n;i++)read(a[i].l),read(a[i].r);
		int mx=0,mn=0x3f3f3f3f,L=-1,R=0x3f3f3f3f;
		for(int i=1;i<=n;i++){
			R=min(R,a[i].r),L=max(L,a[i].l);
			mx=max(mx,a[i].r-a[i].l+1);
			mn=min(mn,a[i].r-a[i].l+1);
		}
		int ans=mx-mn;
		for(int i=1;i<=n;i++){
			ans=max(ans,a[i].r-a[i].l+1-min(max(0,a[i].r-L+1),max(0,R-a[i].l+1)));
		}
		ans<<=1;
		cout<<ans<<"\n";
	}
}

MEX of LCM

题面:
给定一个长度为 n 的序列 a,一个正整数 x 被称为「可爱的」,当且仅当在序列 a 中,不存在一个子段所有元素的 最小公倍数 等于 x。求最小的「可爱数」。

题面一句话,思想两个字:暴力。

注意到,1n+1 个质数至少有一个不会作为某个子段的 lcm 出现,理由是若 lcm 为一个质数,则说明该子段全部为这个数,而最小子段只有 n,而且注意到,当子段左端点固定时,右端点扩张,lcm 单调不减。所以答案上界为第 n+1 个质数,n 取最大值 3×105,则 3×105+1 个质数为 4256233,大于它的全部舍掉。

对于求解存在性的答案,可以通过估计答案上界的办法减少复杂度,mex问题是一个典型

那么,我们只需要求出所有不大于 4256233lcm 即可,我们考虑递推,由小段到大段求解。

这里我们记 f(l,r)=lcm(al,al+1,ar),记 gi={f(i,i),f(i,i+1)f(i,n)},则 gi={ai}{lcm(ai,x),xgi+1}

我们暴力自后向前转移即可。时间复杂度为什么是对的?因为由 in 的路上,lcm 要么不变,要么至少乘2,而这最多乘 log24256233 次。

而注意到求 lcm 需要 gcd,所以时间复杂度是 O(nlog2V),足以通过本题。

但真的没有优化空间了吗?

我们依次合并 lcm(f(i+1,i+1),ai),lcm(f(i+1,i+2),ai),注意到 f(i,j)|f(i,j+1),所以 gcd(f(i+1,i+k),ai)=gcd(gcd(f(i+1,i+k+1),ai),f(i+1,i+k))

由此,我们从 f(i+1,n)f(i+1,i+1) 合并,均摊一次转移执行一次 gcd,时间复杂度降为 O(nlogV)

注意空间可能有点卡,这里可以滚掉。

int t,a[N],n,f[2][105],g[N<<1],d[2],tot,vis[N<<1];
const int lim=4300000;
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
signed main(){
	read(t);
	while(t--){
		read(n);tot=d[0]=d[1]=0;
		for(int i=1;i<=n;i++)read(a[i]);
		for(int i=n;i;i--){
			int x=i&1,y=a[i];d[x]=0;
			for(int j=1;j<=d[x^1];++j){
				ll k=1ll*a[i]*f[x^1][j]/(y=gcd(y,f[x^1][j]));
				if(k<=lim&&k!=f[x][d[x]]){
					f[x][++d[x]]=k;g[++tot]=k;
				}
			}
			if(f[x][d[x]]!=a[i]&&a[i]<=lim)f[x][++d[x]]=g[++tot]=a[i];
		}	
		for(int i=1;i<=tot;i++)vis[g[i]]=1;
		for(int i=1;i<=lim;i++)if(!vis[i]){
			print(i);puts("");break;
		}
		for(int i=1;i<=tot;i++)vis[g[i]]=0;
	}
}

Typewriter

题面:

最近,Polycarp收到了一台特殊的打字机作为礼物!不幸的是,这台打字机有一个相当奇怪的设计。

这台打字机由 n 个单元组成,从左到右编号为 1n ,还有一个移动的小车。打字机的每个单元包含 n 个不同的整数,从 1n ,每个单元 i 最初包含整数 pi 。在所有操作之前,小车位于第一个单元上,它的缓冲区没有任何内容。当前小车所在的单元称为当前单元。

小车可以执行以下五种操作:

  • 如果当前单元不为空,就将其中的整数放入小车的缓冲区(缓冲区最多只能容纳一个整数)。
  • 如果小车的缓冲区不为空,就将其中的整数放入当前单元(如果当前单元为空)。
  • 如果小车的缓冲区和当前单元都含有整数,就交换缓冲区中的整数和当前单元中的整数。
  • 将小车从当前单元 i 移动到下一个单元 i+1 (如果 i<n ),缓冲区中的整数保持不变。
  • 将小车重置,即将其移动到第一个单元,缓冲区中的整数保持不变。

Polycarp对这个打字机非常感兴趣,所以他请你帮助他理解它,并回答他 q 个问题:

  1. 执行一个循环左移 kj 的操作。
  2. 执行一个循环右移 kj 的操作。
  3. 反转序列。

在每个查询之前和之后,Polycarp想要知道为了将数字分配到它们的单元(使数字 i 最终位于第 i 个单元),需要多少次小车重置的最小次数。

注意,Polycarp只想知道需要多少次小车重置来整理数字的位置,但实际上并不进行分配。(也即询问间互相影响)

帮助Polycarp找到每个查询的答案!

题解:

有意思的题目。和 E 一样,我们可以先粗略估计一下答案的上下界。注意到答案的下界即为:i=1n[pi<i],对于每一对 [pi<i] 而言,必然需要重置一次才能使其回到原位。

而,考虑构造一个足够优秀的方案,使得答案足够逼近下界。

我们考虑按 pi 大小解决每一对矛盾,在每一次重置之前,都将 pi 装在缓存区,然后重置,将 pi 放回原位,同时将原来 [pi,i1] 的数整体移动到 [pi+1,i],这样既不会对其他矛盾对产生影响,也不会产生新的矛盾(因为按了 pi 至小到大)。实在不行直接观察样例嘛。。。

那么我们的问题就变成了:维护在操作互相关联,支持区间循环和区间翻转操作的 i=1n[pi<i] 的个数。

我们直接将区间翻转单开一个翻转后的序列,一起维护两个序列,答案则根据当前属于哪个序列就输出哪个。

首先注意到,左移 i 次,等价于右移 ni 次。所以我们也可以将左右移只化作右移。注意对于翻转后的序列而言,右移相当于左移

那么,问题就变成了超简化版:求出 ansk(0k<n),表示所有下标在 1n 循环中移动 k 位后的答案。

当然,这不能暴力,但化整为零,对于每个数而言,它的贡献具有两段性。

以当前 pi<ii 举例,当 0kni 时,对答案没有影响,但 ni+1kni+pi 时,这个数的贡献少了 1,所以 anskansk1(ni+1kni+pi)

而对于 piii 而言,当 pii+1kni 时,anskansk+1

发现答案的变化量是一个区间赋值问题,可以使用差分解决。

对于翻转后序列,直接开另一个差分即可。

int a[N],opt,n,t,k,ans,c1[N],cnt,c3[N];
signed main(){
	read(n);
	for(int i=1;i<=n;i++)read(a[i]);
	for(int i=1;i<=n;i++)ans+=(a[i]<i),cnt+=(a[n-i+1]<i);
	print(ans);puts("");
	for(int i=1;i<=n;i++){
		if(a[i]<i)c1[n-i+1]--,c1[n-i+1+a[i]]++;
		else if(a[i]-i+1<=n-i)c1[a[i]-i+1]++,c1[n-i+1]--;
	}
	c1[0]=ans;reverse(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		if(a[i]<i)c3[n-i+1]--,c3[n-i+1+a[i]]++;
		else if(a[i]-i+1<=n-i)c3[a[i]-i+1]++,c3[n-i+1]--;
	}
	c3[0]=cnt;
	for(int i=1;i<=n;i++)c1[i]+=c1[i-1],c3[i]+=c3[i-1];
	read(t);int d1=0,d2=0,tag=0;
	while(t--){
		read(opt);
		if(opt==3)tag^=1;
		else if(opt+tag==2){read(k);d2=(d2-k+n)%n;d1=(d1+k)%n;}
		else {read(k);d2=(d2+k)%n;d1=(d1-k+n)%n;}
		if(tag)print(c3[d2]);
		else print(c1[d1]);
		puts("");
	}
}

唉,这个F比较水,只有*2500

Summarize the tricks

  1. 在一定限制下排除一定不优的决策——D
  2. 估计答案上下界,并考虑构造尽可能接近上/下界的答案——E
  3. 化整为零,考虑每一个元素对答案的影响——F
posted @   spdarkle  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示