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;
}
posted @ 2025-02-09 10:11  LaDeX  阅读(17)  评论(0)    收藏  举报