首先因为是全排列,所以和 \(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_{n,i}\) 的 \(\gcd\)。
算法 2
妈妈,我会形式幂级数!妈妈,我会生成函数!
考虑构造生成函数:
根据递推式:
然后得到:
然后答案就是 \(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\),得证。
回到原问题,我们把递推式展开得到:
我们把这么多项 \((a_ix+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;
}