Codeforces 1834 / Codeforces Round #879 (Div. 2)

Codeforces Round #879 (Div. 2)

Problem B Maximum Strength#

题意

给定 L,R,求两个整数 La,bR 使得 a,b 的数位差之和最大。例如 133219 的数位差是 |12|+|31|+|39|=9,位数不足用前导零补齐。

1LR<10100

题解

考场上脑子瓦特了,想的 DP:钦定 ab。设 f(i,0/1,0/1,0/1) 分别表示高 ia 是否一直处于下界,b 是否处于上界,是否已经选取的位有 a=b,然后枚举当前位选的数,判断是否合法。

但事实上我们发现答案最大就是找到最高的位使得 L,R 的这一位 li,ri 不同,然后 a 的这一位选 rib 的这一位选 li,之后 a 一直选 0b 一直选 9

例如:L=558244,R=559244,取 a=559000,b=558999 最优。

Problem C Game with Reversing#

题意

Alice Bob 玩游戏。现在有两个长为 n 的小写字母串 S,T,从 Alice 开始轮流操作,Alice 可以选择串里的某个位置,改成另一个小写字母(可以和原来相同),Bob 可以选一个串进行翻转。

Alice 想要游戏尽快结束,Bob 想要游戏尽可能长。求游戏结束时总共操作了多少次。

1n105

题解

我们发现 Bob 的具体操作策略对答案没有影响,因为翻两次 S 和翻一次 S,翻一次 T 本质相同。我们只需要关心游戏结束时,Bob 究竟操作了多少次。如果操作了奇数次,Alice 必须把 S 改的和 T 的反串相同,否则必须把 ST 改的相同。

我们进一步发现,Alice 的操作次数只和 ST(或其反串的差异)有关。于是分类讨论 Bob 操作次数的奇偶性,然后计算 Alice 的操作次数即可。注意有可能在 Bob 操作偶数次的情况下,Alice 需要操作的次数是一个奇数(比如 5),这个时候 Alice 必须要放空一轮,等 Bob 的第 6 次操作。同理另一侧也有一些特殊情况,处理一下即可。

Problem D Survey in Class#

题意

现在有 n 个学生,m 个学科,第 i 个学生只会 [li,ri] 的学科的问题。现在你作为老师,可以问一些学科的问题,当然,每一科最多问一次。初始每个学生的手高度为 0。如果学生会该问题,则手的高度增加 1,否则减少 1。问在所有可能的问法中,最后学生中最高的手和最低的手的高度差最大是多少。

2n105,1lirim109

题解

考虑钦定两个学生是最高的和最低的。发现问他们都会的和都不会的都没有意义。只需要问一个人会的,另一个人不会的,才会拉开差距。设两个人会的集合分别是 a,b,那么要求的就是最大的 |a||ab|

考虑 b 怎么交 a:要么和 a 的左端点交,要么和 a 的右端点交,要么完全在 a 内部。于是,我们只需要检查三条线段:右端点最小的,左端点最大的,长度最小的。如果其中某些线段和 a 没有交,那无疑是更优的。

有瓜皮考场上写了线段树。😃

Problem E MEX of LCM#

题意

给定长度为 n 的正整数数组 a,问最小的正整数 x 使得不存在任何区间的 LCM 为 x

1n3×105,1ai109

题解

注意到 n2 个数的 MEX 不超过 n2+1,于是只有 LCM 小于等于 n2+1 的才可能成为答案。这也说明,同一右端点的所有区间,至多只有不同的 2log2n+1 个 LCM 可能成为答案:设这些 LCM 分别为 x1<x2<<xk,显然有 xi+1xi 整除,从而 xi+12xi

到这里已经可以暴力向右移动端点,然后做完了。

同时,上面的方法也证明了答案甚至是不超过 109 的,于是我们不用担心溢出。

Problem F Typewriter#

题意

给定一个长度为 n 的排列 p,初始有一个指向 1 的指针和一个空的缓冲区。

你可以执行以下操作:

  • 如果当前指针指向的位置非空且缓冲区是空的,把这个位置上的数扔进缓冲区
  • 如果缓冲区非空且当前指针指向的位置是空的,把缓冲区中的数扔到这个位置
  • 如果它们都非空,交换这两个数
  • 指针右移 1
  • 指针移回 1

现在有 q 次操作,形如:

  • 排列向左循环移位 k
  • 排列向右循环移位 k
  • 翻转排列

在第一次操作前和每次操作后,询问使用上述操作将当前排列变为 1,2,,n 的最小指针移回 1 的次数。注意到这些操作不会真实发生。

1n4×105

题解

指针只会向右移动,显然每一次指针移回 1 只能让一个 pi<i 的位置归位,于是答案的下界就是满足条件的 i 数量。同时,我们可以构造出这个下界:每次把 pi 位置的数拿起,到 i 位置执行交换,指针移回 1,最后到 pi 位置放下。为了操作冲突最小,我们按照 pi 从小到大对于所有符合条件的 i 操作即可。

现在问题就是怎么维护 pi<i 的位置数量。首先观察到左移和右移没有本质区别,我们只需要维护数组的开头是哪些位置的时候,pi<i 成立。不难发现这是一个连续段(也有可能是前缀 + 后缀),差分即可。

对于翻转,我们直接对于翻转后的 p 也维护上面的即可。考虑翻转后,左移和右移的意义恰好与翻转前相反,维护即可。

# include <bits/stdc++.h>

const int N=400010,INF=0x3f3f3f3f;

int n,q;

int T;

inline int read(void){
	int res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-')f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}

int p[N];

struct Node{
	int a[N],ans[N];
	inline void init(bool op){
		for(int i=1;i<=n;++i) a[i]=p[op?(n-i+1):i],ans[i]=0;
		for(int i=1;i<=n;++i){ // ai < i
			if(a[i]<=i) ++ans[1],--ans[i-a[i]+1],++ans[i+1],--ans[n+1];
            // [1,i-ai] and [i+1,n] when ai<=i; [i+1,n-(ai-i)] when ai>i; 
			else ++ans[i+1],--ans[n-(a[i]-i)+1];
		}
		for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
		return;
	}
}sim,rev;


int main(void){
	T=1;
	while(T--){
		n=read();
		for(int i=1;i<=n;++i) p[i]=read();
		q=read();
		sim.init(false),rev.init(true);
		int sh=0,re=1;
		
		printf("%d\n",sim.ans[1]);
		while(q--){
			int op=read(); // + : left shift - : right shift
			if(op==1) sh+=read()*re;
			else if(op==2) sh-=read()*re;
			else re*=-1;
			sh=(sh%n+n)%n;
			if(re==1) printf("%d\n",sim.ans[sh+1]);
			else printf("%d\n",rev.ans[(n-sh)%n+1]); // reversed
		}
	}

	return 0;
}

作者:Meatherm

出处:https://www.cnblogs.com/Meatherm/p/17492416.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Meatherm  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
历史上的今天:
2022-06-19 【瞎口胡】后缀自动机(SAM)
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示