CF1848F

[CF1848F] Vika and Wiki

shaber 题没想出来,紫砂了。

这种题的经典方法是考虑贡献,注意到顺着想贡献不容易我们倒过来想,设 \(f_{i,j}\) 表示 \(i\) 轮后 \(j\) 的大小,则 \(f_{i,j}=\operatorname{xor}\limits_{k\in [0,i]} \binom{i}{k}\bmod 2\ \times a_{(j+k)\bmod n}\)

然后根据 [CTSC2017] 吉夫特 我们知道中间那个组合数有贡献当且仅当 \(k\)\(i\) 的子集。

因为 \(n\) 是二的次幂,所以 \(f_{n,p}=0\)。于是上界卡到 \(n\)

然后考虑高维前缀和,因为 \((j+k)\bmod n\) 很难处理,我们先考虑一个特殊的 \(0\),这个是简单的,然后考虑什么时候 \(x\) 可以成为答案。如果 \(x\) 时刻 \(f_{x,0}=0\)\(\exist i\in (0,n),f_{x,i}\neq 0\),则 \(f_{x+i,0}\neq 0\),所以这个条件等价于 \(\forall i\in [x,+\infty),f_{i,0}=0\),然后我们知道这个答案上界是 \(n\) 所以倒着枚举即可。\(\mathcal O(n\log n)\)

#include <bits/stdc++.h>
#define pb emplace_back
#define fir first
#define sec second

using i64 = long long;
const int maxn = 1 << 20;
int n, a[maxn];

int main() {
	scanf("%d", &n);
	for(int i = 0;i < n;++ i)
		scanf("%d", &a[i]);
	for(int i = 0;(1 << i) < n;++ i)
		for(int j = 0;j < n;++ j)
			if(j >> i & 1)
				a[j] ^= a[j ^ (1 << i)];
	for(int i = n - 1;~ i;-- i)
		if(a[i]) return printf("%d\n", i + 1), 0;
	puts("0");
	return 0;
}
posted @ 2023-08-10 20:18  ImALAS  阅读(21)  评论(0编辑  收藏  举报