AT_dwacon5th_prelims_e Cyclic GCDs Solution
首先因为是全排列,所以和 \(a_i\) 相对位置无关,对其排序,则每个轮换的权值就是最左边的数。
算法 1
妈妈,我会 DP!定义 \(f_{i,j}\) 表示前 \(i\) 个数,组成了 \(j\) 个轮换。我们有两种转移:
- 把新加入的数放在一个新轮换中,则新轮换的权值就是其本身:\(f_{i,j}\leftarrow f_{i-1,j-1}\times a_i\)。
- 把新加入的数放在之前的轮换之后,则有 \(i-1\) 个空位可以放:\(f_{i,j}\leftarrow f_{i-1,j}\times (i-1)\)。
即:
\[f_{i,j}=(i-1)f_{i-1,j}+a_if_{i-1,j-1}.
\]
答案就是 \(f_{n,i}\) 的 \(\gcd\)。
算法 2
妈妈,我会形式幂级数!妈妈,我会生成函数!
考虑构造生成函数:
\[F_i(x)=\sum_{j=0}^n f_{i,j} x^j.
\]
根据递推式:
\[[x^j]F_i(x)=(i-1)[x^j]F_{i-1}+a_i[x^{j-1}]F_{i-1}.
\]
然后得到:
\[F_i(x)=(a_ix+i-1)F_{i-1}(x).
\]
然后答案就是 \(F_n(x)\) 的各项系数的 \(\gcd\)。但是我不会求。
算法 3
妈妈,我会高斯引理!
有结论:两个整系数多项式乘积的各项系数的 \(\gcd\) 等于两个多项式各项系数的 \(\gcd\) 的乘积。
证明:设这两个多项式分别为 \(F(x),G(x)\),系数 \(\gcd\) 分别为 \(a,b\),则 \(F(x)=af(x),G(x)=bg(x)\),其中 \(f(x),g(x)\) 都是本原多项式(系数互质)。观察乘积,\(H(x)=F(x)G(x)=abf(x)g(x)\),根据高斯引理,两个本原多项式乘积依然是本原多项式,所以 \(h(x)=f(x)g(x)\) 也是系数都互质的,所以 \(H(x)\) 的系数的 \(\gcd\) 就是 \(a\times b\),得证。
回到原问题,我们把递推式展开得到:
\[F_n(x)=\prod(a_ix+i-1).
\]
我们把这么多项 \((a_ix+i-1)\) 依次相乘,根据结论,答案就是:
\[\text{Answer}=\prod \gcd(a_i,i-1).
\]
注:\(i=1\) 时 \(\gcd\) 就是 \(a_1\) 自身。
然后就做完了。代码极其短。为什么我没有场切 /ll。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 1e6 + 10;
const LL MOD = 998244353;
int A[N], n;
int main() {
freopen(".in", "r", stdin); freopen(".out", "w", stdout);
ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n; for (int i = 1; i <= n; i ++) cin >> A[i];
sort(A + 1, A + 1 + n); LL Ans = A[1];
for (int i = 1; i < n; i ++) Ans = Ans * __gcd(A[i + 1], i) % MOD;
cout << Ans << "\n";
return 0;
}

浙公网安备 33010602011771号