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
k
k 求有多少种情况的贡献
⩾
k
\geqslant k
⩾k。
那
⩾
k
\geqslant k
⩾k 的数变成
1
1
1,
<
k
<k
<k 的数变成
0
0
0。
于是只有
0
,
1
0,1
0,1 问题看上去似乎可以做了。
发现如果
(
a
,
0
,
0
)
(a,0,0)
(a,0,0) 或者
(
a
,
1
,
1
)
(a,1,1)
(a,1,1) 这种出现了,那就跟
a
a
a 没关系了。
我们就只需要看看最后是
0
0
0 还是
1
1
1。
然后其实有一个东西叫做对称性,就是
k
=
p
k=p
k=p 的时候
0
0
0 的个数和
k
=
v
−
p
k=v-p
k=v−p 的时候
1
1
1 的个数是一样的。
而
k
k
k 等于啥的时候贡献都是
1
1
1,所以我们只需要求出所有
k
k
k 跟
a
a
a 无关的情况数,除二即可。
接着考虑数跟
a
a
a 有关的情况数,无关的数量可以用全部减去有关的。
那就是全程都是
(
a
,
0
,
1
)
(a,0,1)
(a,0,1) 这种。
那因为有循环,所以独立的行和列只有
gcd
(
n
,
m
)
\gcd(n,m)
gcd(n,m) 个。
别的会因为能匹配到而要求相同。(匹配你把所有左侧点的
(
i
−
1
)
%
n
+
1
(i-1)\%n+1
(i−1)%n+1,跟右侧点的
(
i
−
1
)
%
m
+
1
(i-1)\%m+1
(i−1)%m+1 连边, 表示这些之间要不同)
(然后由于是二分图,一个连通块中左侧点和右侧点分别都要一样,而且互相之间还要不同,所以是固定了)
然后再根据谁是
0
0
0 谁是
1
1
1,能统计方案:
(
k
n
/
gcd
(
v
−
k
)
m
/
gcd
+
(
v
−
k
)
n
/
gcd
k
m
/
gcd
)
gcd
(k^{n/\gcd}(v-k)^{m/\gcd}+(v-k)^{n/\gcd}k^{m/\gcd})^{\gcd}
(kn/gcd(v−k)m/gcd+(v−k)n/gcdkm/gcd)gcd
(里面每一组可以选的,然后有
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;
}