【ARC133E】Cyclic Medians(数学)

Cyclic Medians

题目链接:ARC133E

题目大意

给你四个数 n,m,v,a,然后你可以选择两个长度分别为 n,m,值域在 1~v 之间的数组 x,y。
有一个数 A 初始值为 a,然后进行 nm 次变换,第 i 次把 A,x[(i-1)%n+1],y[(i-1)%m+1] 的中值作为新的 A。
问你对于每一对可能的数组 x,y,求 A 的最终值的和。

思路

直接求不好搞,考虑对于每个 \(k\) 求有多少种情况的贡献 \(\geqslant k\)
\(\geqslant k\) 的数变成 \(1\)\(<k\) 的数变成 \(0\)

于是只有 \(0,1\) 问题看上去似乎可以做了。
发现如果 \((a,0,0)\) 或者 \((a,1,1)\) 这种出现了,那就跟 \(a\) 没关系了。
我们就只需要看看最后是 \(0\) 还是 \(1\)
然后其实有一个东西叫做对称性,就是 \(k=p\) 的时候 \(0\) 的个数和 \(k=v-p\) 的时候 \(1\) 的个数是一样的。
\(k\) 等于啥的时候贡献都是 \(1\),所以我们只需要求出所有 \(k\)\(a\) 无关的情况数,除二即可。

接着考虑数跟 \(a\) 有关的情况数,无关的数量可以用全部减去有关的。
那就是全程都是 \((a,0,1)\) 这种。
那因为有循环,所以独立的行和列只有 \(\gcd(n,m)\) 个。
别的会因为能匹配到而要求相同。(匹配你把所有左侧点的 \((i-1)\%n+1\),跟右侧点的 \((i-1)\%m+1\) 连边, 表示这些之间要不同)
(然后由于是二分图,一个连通块中左侧点和右侧点分别都要一样,而且互相之间还要不同,所以是固定了)
然后再根据谁是 \(0\) 谁是 \(1\),能统计方案:
\((k^{n/\gcd}(v-k)^{m/\gcd}+(v-k)^{n/\gcd}k^{m/\gcd})^{\gcd}\)
(里面每一组可以选的,然后有 \(\gcd\) 组独立的)

然后就好啦。

代码

#include<cstdio>
#define ll long long
#define mo 998244353

using namespace std;

int n, m, v, a, g;
ll ans;

ll gcd(ll x, ll y) {
	if (!y) return x;
	return gcd(y, x % y);
}

ll ksm(ll x, ll y) {
	ll re = 1;
	while (y) {
		if (y & 1) re = re * x % mo;
		x = x * x % mo; y >>= 1;
	}
	return re;
}

int main() {
	scanf("%d %d %d %d", &n, &m, &v, &a); g = gcd(n, m);
	
	ll all = ksm(v, n + m), inv2 = (mo + 1) / 2;
	ans += all;
	for (int lim = 2; lim <= v; lim++) {
		ll num_no = ksm((ksm(lim - 1, n / g) * ksm(v - lim + 1, m / g) % mo + ksm(v - lim + 1, n / g) * ksm(lim - 1, m / g) % mo) % mo, g);
		if (a >= lim) (ans += num_no) %= mo;
		ll num_yes = (all - num_no + mo) % mo;
		(ans += num_yes * inv2 % mo) %= mo;
	}
	printf("%lld", ans);
	
	return 0;
}
posted @ 2022-10-20 10:09  あおいSakura  阅读(61)  评论(0)    收藏  举报