WorldQuant Round 1 (Codeforces Round 1128, Div. 1 + Div. 2)

主播主播你的罚时怎么这么多?

小号的第五场1473(+174)也是成功上青了,感觉打小号比大号顺利多了。

A(+1)

题面

Souvlakity 和 Kalamakity 又在玩另一个游戏。

所有从 \(1\) 到 \(n\) 的整数已经被分配给了这两位玩家。这个分配可以用一个大小为 \(n\) 的二进制字符串 \(s\) 表示,其中如果整数 \(i\) 被分配给了 Souvlakity,则 \(s_i = 1\),如果它被分配给了 Kalamakity,则 \(s_i = 0\)。保证 Souvlakity 初始时至少拥有一个整数(\(s\) 中存在一个 \(1\))。

游戏将持续 \(10^{100}\) 个回合。两位玩家轮流行动,Souvlakity 先手。

当轮到某位玩家行动时,他必须恰好选择自己的一个整数并将其交给另一位玩家。可以证明,在此游戏的约束下,这总是可能的。

在所有 \(10^{100}\) 个回合结束后,Souvlakity 计算他的得分为他所拥有的整数的极差(即他的得分为 \(\max(S) - \min(S)\),其中 \(S\) 是他所拥有的整数集合)。可以证明,Souvlakity 在游戏结束时将至少拥有一个整数。

Souvlakity 想要最大化他的得分,而 Kalamakity 想要最小化 Souvlakity 的得分。如果两位玩家都采取最优策略,Souvlakity 的最终得分是多少?

思路

本质简单题(wa了一发唐完了兄弟),设 \(c\) 为初始有的数字数量,考虑如下几种情况

  • \(c=1\) 显然答案为 \(1\).
  • \(c=2\) 在最后总是可以构造出极差为 \(1\) 的结果。
  • \(c>2\) Souvlakity的每次操作都可以被撤销,择结果就是原序列的极差。

B(+3)

题面

Obesity 可能不知道法国的首都是哪里,但他知道法国有很多餐厅。

有 \(n\) 家餐厅排成一排。第 \(i\) 家餐厅的评分为 \(a_i\)。

Obesity 可以用他的特殊能力改变餐厅的评分。在一次操作中,Obesity 选择两家相邻的餐厅。如果它们评分相同,则什么都不会发生。否则,评分较低的那一侧增加 \(1\)。

正式地,在一次操作中,他执行以下步骤:

  • 选择一个下标 \(i\)(\(1 \le i \lt n\))。
  • 如果 \(a_i \lt a_{i+1}\),则将 \(a_i\) 增加 \(1\)。
  • 如果 \(a_i = a_{i+1}\),则不进行操作。
  • 如果 \(a_i \gt a_{i+1}\),则将 \(a_{i+1}\) 增加 \(1\)。

所有餐厅评分的 按位或(bitwise OR) 值被称为这些餐厅的 美味度。

请问 Obesity 在执行零次或多次操作后,能获得的最大美味度是多少?

思路

注意注意,前方按位或来袭。赛事题目看错了,把按位或看成按位异或了,浪费了十几分钟。根据题目我们会发现最大值是不能增加的,要让美味度最大,考虑从高位到地位按位贪心。最高位一定存在,由于按位或的性质,每一位只需要有一位存在 \(1\) 即可,所以我们事实上只需要考虑两个数字就可以了,设最大值为 \(max\),最小值为 \(min\),新的值 \(min<=x<=max\),根据二进制的性质,我们找到 \(min\) 与 \(max\) 不同的第一个二进制位置,这个位置一定是 \(max\) 为 \(1\) 且 \(min\) 为 \(0\),若该位置是 \(1\),则可以直接补齐,否则就把这一位之后的二进制都补齐。

C(+2)

题面

Moggity 和 Larpity 正在用一个由正整数组成的数组 \(a_1, a_2, \ldots, a_n\) 玩游戏。Moggity 先手,然后两人轮流行动。

轮到一名玩家行动时,他需要选择一个非空的数组位置集合,并移除这些位置上的元素。只有当满足以下至少一个条件时,该移动才是允许的:

  • 只移除恰好一个元素;
  • 被移除的元素之和为偶数。

无法进行合法移动的玩家输掉游戏。换句话说,面对空数组的玩家输掉游戏。

请判断哪位玩家有必胜策略。

思路

显然,是根据奇数和偶数的数量判断。我们来分类讨论,我们设奇数的数量为 \(cnt1\),偶数的数量为 \(cnt2\).

  • \(n=1\) 显然 Moggity 必胜。
  • \(cnt1\) 为偶数,此时 Moggity 也可以一步拿完,必胜。
  • \(cnt1\) 为奇数,若 \(cnt1=1,cnt2=1\) Laripity 必胜;若 \(cnt1=1,cnt2>1\) Moggity 必胜;若 \(cnt1=3,cnt2=0\) Lariptiy 必胜,否则 Moggity 必胜。

D1(+1)很有意思的构造

题面

你正在躲避强大的 Verity 领主。

有一排共 \(n\) 个可能的藏身点,从左到右编号为 \(1\) 到 \(n\)。你会藏在恰好其中一个藏身点中。

为了找到你,Verity 领主可以安装特殊的探测器。每个探测器覆盖一段连续的藏身点,并报告你是否藏在该段中的某个藏身点内。所有探测器同时激活,因此所有探测器的检测区间必须在任何报告得知之前选定。

Verity 领主已经有 \(m\) 个探测器;其中第 \(i\) 个探测器覆盖从 \(l_i\) 到 \(r_i\) 的藏身点。请找出 Verity 领主需要额外安装的最少探测器数量,使得无论你藏在哪里,所有探测器的报告都足以唯一确定你所藏的藏身点。你还需要给出一种安装方案。

思路

这个覆盖问题很奇妙,比赛的时候手玩了一下猜了一种基于类似线段树结构的覆盖方法。我们每一次的覆盖本质是为了区分左右两个区间,对于同一个区间我们可以在左右子区间选择其中一个进行覆盖,这就区分了两个区间;接着看两个相邻的区间,我们可以分成 \(4\) 个子区间,我们发现区间 \(区间2,3\) 可以一起覆盖,然后 \(区间1,4\) 可以不覆盖,这样不断迭代覆盖就好了。然后要注意的一个细节是我们不选择覆盖一个区间不代表这个区间不存在,依旧要加入迭代。

核心代码

while(!d.empty()){
	vector<node>ne;
	for(auto i:d){
		if(i.l==i.r)continue;
		int mid=(i.l+i.r)/2;
		node L,R;
		L.l=i.l;
		L.r=mid;
		R.l=mid+1;
		R.r=i.r;

		ne.push_back(L);
		ne.push_back(R);
	}
	swap(d,ne);
	for(int i=0;i<d.size();i+=4){
		if(i+2<d.size()){
			E.l=d[i+1].l;
			E.r=d[i+2].r;
			ans.push_back(E);
		}else {
			ans.push_back(d[i]);
		}
	}
}

E(+1)极限压力过题

题面

"哦,哞,哞,哞,我平时就是这么说话的!"

—— Bessie 奶牛

Bessie 给你一个长度为 \(n\) 的正则括号序列(RBS)\(^{\text{∗}}\) 和一个整数 \(k\)。

在一次操作中,你可以执行以下步骤:

  • 选择一个下标 \(i\)(\(1 \le i \lt n\)),使得 \(s_i s_{i+1} = \mathtt{()}\)。
  • 令 \(s'\) 表示从 \(s\) 中删除这两个字符后得到的字符串。
  • 令 \(s := \mathtt{(} + s' + \mathtt{)}\)。

你最多可以执行 \(k\) 次操作(也可以不执行)。可以证明,每次这样的操作后,\(s\) 仍然是一个 RBS。

一个 RBS 的得分定义为该字符串中连续的开括号 '\(\texttt{(}\)' 的最大数量。例如,字符串 "\(\texttt{(())((())())}\)" 的得分为 \(3\)。

你的任务是:通过对给定字符串执行最多 \(k\) 次操作,求出你能获得的最大可能得分。

\(^{\text{∗}}\)正则括号序列是指可以通过在原序列的字符之间插入字符 \(1\) 和 \(+\) 来转换为正确的算术表达式的括号序列。例如:

  • 括号序列 \(\texttt{()()}\) 和 \(\texttt{(())}\) 是正则的(转换后的表达式分别为:\(\texttt{(1)+(1)}\) 和 \(\texttt{((1+1)+1)}\));
  • 括号序列 \(\texttt{)(}\)、\(\texttt{(}\) 和 \(\texttt{)}\) 不是正则的。

思路

注意注意,前方括号匹配来袭(bushi)。

我们把若干 "(((" 组成的字串称为一个括号群。
我们要理解操作的本质是尝试联通两个括号群,当当前括号群与序列左侧联通是每一次操作不会减少当前括号群的长度,而当前括号群与左侧不连通时每一次操作会使括号群的长度减少 \(1\).当与左侧联通时我们直接模拟操作就好了。

我们设 \(pre[i]\) 为括号群的前缀和,\(prew[i]\) 为点 \(i\) 到点 \(i+1\) 的右括号数量的前缀和。

当与左侧不连通时我们设当前的起点为 \(i\),与第 \(j\) 个点联通,得到的新括号群长度为 \(pre[j]-pre[i-1]-(prew[j-1]-prew[i-1])\) 发现对于同一个 \(i\) 最终长度只和 \(pre[j]-prew[j-1]\) 有关。我们可以通过线段树来维护 \(pre[j]-prew[j-1]\) 的区间最值,然后通过在 \(prew\) 上面做二分来决定最多可以联通到哪个点,最后枚举起点即可

核心代码

for(int i=1;i<=cnt;i++){
	int l=i,r=cnt;
	int p=i;
	while(l<=r){
		int mid=(l+r)/2;
		if(prew[mid-1]-prew[i-1]<=k){
			p=mid;
			l=mid+1;
		}else r=mid-1;
	}
	ans=max(ans,t.qry(i,p)-pre[i-1]+prew[i-1]);
}
posted @ 2026-10-19 12:15  逃跑大师在这里  阅读(27)  评论(0)    收藏  举报