「题解」AGC010D Decrementing

「题解」AGC010D Decrementing

序列中至少有一个奇数,否则就会被 gcd 除掉了。

如果序列出现了 1,说明无论怎样操作之后 gcd 都只能为 1 了,那么判断偶数个数的奇偶性,若有奇数个偶数那么先手必胜,判掉这个,现在所有的数都是可以被钦点的了。

猜个结论,如果有奇数个偶数,那么先手必胜。

注意到如果钦点一个数 1 之后,剩余既有奇数又有偶数,则 gcd 为奇数,除掉 gcd 之后各个数的奇偶性不变。

那么先手只需要钦点使得给后手 >1 个奇数,>0 个偶数,这样后手无论怎么钦点,轮到先手的时候依然是奇数个偶数。

那么特殊情况就是 n=2 的时候,这个稍微讨论一下就差不多得了发现依然满足结论。

然后看如果先手有偶数个偶数,考虑奇数的个数,如果奇数的个数 >1,那先手不管怎么钦点,轮给后手的都是"奇数个偶数"的必胜状态,所以此时先手必败。

如果奇数的个数 =1,先手如果钦点偶数的话,轮给后手的就是"奇数个偶数"的必胜状态,所以先手之能钦点奇数,这种情况递归下去继续判即可。

每产生一次递归,所有数至少变为原来的一半,所以总复杂度就是 O(Nlog2A)

就嗯塞语法糖

#include<iostream>
#include<cstdio>
template <typename T>
T &read(T &r) {
	r = 0; bool w = 0; char ch = getchar();
	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
	return r = w ? -r : r;
}
const int N = 100010;
int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }
int n, a[N];
#define Win do{puts(p?"Second":"First");return ;}while(0)
#define Lose do{puts(p?"First":"Second");return ;}while(0)
void check(int p) {
	int ct = 0, g = 0, fl = 0;
	for(int i = 1; i <= n; ++i)
		ct += !(a[i]&1),
		g = a[i]&1 ? gcd(g, a[i]-1) : gcd(g, a[i]),
		fl |= a[i]==1;
	if(ct&1) Win;
	if(fl || n-ct>1) Lose;
	for(int i = 1; i <= n; ++i) a[i] = a[i]&1 ? (a[i]-1)/g : a[i]/g;
	check(p^1);
}
signed main() {
	read(n);
	for(int i = 1; i <= n; ++i) read(a[i]);
	check(0);
	return 0;
}
posted @   do_while_true  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1845 days 1 hours 33 minutes 23 seconds

点击右上角即可分享
微信分享提示