题解:P17206 「DLESS-6」Lost Requiem

· · 题解

我说我最后写出的式子,怎么长的那么像 Burnside?!不知道呀……

观前提示:本题解不直接使用 Burnside 引理,虽然我也不知道是不是相当于证明了一遍(挠头)

前置知识:原根。对任意奇质数 p,一定存在原根 g1<g<p)。g 满足:最小的使 g^e\equiv 1\pmod p 的正整数 ep-1g 有性质,g\bmod p,g^2\bmod p,\dots,g^{p-1}\bmod p 恰遍历 1,2,\dots,p-1 各一次

由于 n 为质数,不难发现题目所述变换 f 是可逆的。因此,所有可能的序列 a 构成若干等价类,每个等价类内恰有一个序列符合条件。

令一个序列 a权值为所在等价类的大小的倒数,则所求答案即为所有序列 a 的权值和。我们转而刻画权值。

继续寻找等价类的性质。注意到 f 变换不仅可逆,而且两个 f 变换的复合也可用一个 f 变换表示——本质上,f 是对下标的线性变换。这样,一个等价类内的两个序列,一定可以通过一次 f 变换互相转换。

考虑共有 n(n-1) 种不同的 f 变换。对于一个序列 a,若其中有 t 种变换相当于恒等变换(即,将 a 变换到 a),由于序列的对称性,a 所在的等价类内,所有序列均有 t 种恒等变换。结合「一个等价类内的两个序列,一定可以通过一次 f 变换互相转换」,可以推知,等价类大小为 \dfrac{n(n-1)}{t}

若然,a 序列对答案的贡献为 \dfrac{t}{n(n-1)}。答案为

\sum_a\frac{t}{n(n-1)}=\frac{1}{{n(n-1)}}\sum_a t

需要计算所有序列 a 的恒等变换数之和。考虑「算两次」,计算一个变换 f 的贡献——有多少个序列 a,在 f 下变换导致恒等。

考虑变换 f(a,x,y),将下标变换:i\to xi+y。序列 a 在对任意 i=0,1,\dots,n-1a_i=a_{(xi+y)\bmod n} 时,才有 f(a,x,y)=a。若构建一个点编号 0,1,\dots,n-1 的图,连边 (i,xi+y),则序列 a 的个数为 m^cc 为图的连通块个数。

下求出 c。分类讨论:

考虑 f 将下标变换:i\to xi+y,若将序列旋转移位 \Delta(下标 i\to i+\Delta),则变换 f 的效果变为 i+\Delta\to xi+y+\Delta。令 x\Delta=y+\Delta,则变换相当于 i\to xi,等效于 y=0。这只需 \Delta=\frac{y}{x-1},由于 x\neq 1n 为质数,\Delta 在模 n 意义下存在。

接下来只需对 y=0c

e 是最小的正整数,使 x^e\equiv 1\pmod n,则一个不含 0 的连通块的大小为 e,而 0 自成一个连通块。因此,c=\dfrac{n-1}{e}+1

考虑 n 的一个原根 g,由 2\le x\le n-1,假设 x=g^l1\le l\le n-2)。那么 g^{le}\equiv 1\pmod n,于是 n-1\mid lee 的最小值为 \dfrac{n-1}{\gcd(n-1,l)}

代入 c 得到 c=\gcd(n-1,l)+1。因此这部分的贡献为

\sum_{l=1}^{n-2}m^{\gcd(n-1,l)+1}

考虑枚举 d=\gcd(n-1,l),这要求 d\neq n-1d\mid l\gcd(\dfrac{n-1}{d},\dfrac{l}{d})=1。在 \dfrac{l}{d}=1,2,\dots,\dfrac{n-1}{d}-1 中,满足要求的 l\varphi(\dfrac{n-1}{d}) 个。

于是,以上求和式化为

\sum_{d\mid n-1,d\neq n-1}m^{d+1}\varphi(\frac{n-1}{d})

d\gets \frac{n}{d},即为

\sum_{d\mid n-1,d\neq 1}m^{\frac{n-1}{d}+1}\varphi(d)

至此两部分贡献均可计算,答案为:

\frac{1}{{n(n-1)}}\sum_a t=\frac{1}{{n(n-1)}}(m^n+(n-1)m+\sum_{d\mid n-1,d\neq 1}m^{\frac{n-1}{d}+1}\varphi(d))

考虑将 n-1 分解质因数,深搜其约数,在深搜的每一层,枚举某个质因子的指数并递推计算 \varphi(d),这样即可快速计算答案。

::::info[Code]

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200004
ll n,m,p,in;
ll qpow(ll a,ll b){
    ll r=1;
    while(b)(b&1)&&(r=r*a%p),a=a*a%p,b>>=1;
    return r;
}
#define inv(x) qpow(x,p-2)
inline int read(){
    static char c;
    static int r;r=0;
    while(c<48||c>57)c=getchar();
    while(c>47&&c<58)r=(r<<1)+(r<<3)+(c^48),c=getchar();
    return r;
}
vector<pair<ll,int> > getp(ll n){
    vector<pair<ll,int> > res;
    for(ll r=2;r*r<=n;++r){
        int c=0;
        while(n%r==0)n/=r,++c;
        if(c)res.push_back({r,c});
    }
    if(n>1)res.push_back({n,1});
    return res;
}
vector<pair<ll,int> > v;
ll ans;
void dfs(int t,ll d,ll phi){
    if(t==v.size()){
        if(d==1)return;
        ans=(ans+qpow(m,(n-1)/d+1)*phi%p*n)%p;
        return;
    }
    int m=v[t].first;
    dfs(t+1,d,phi);
    d*=m,phi*=(m-1);
    for(int i=0;i<v[t].second;++i)dfs(t+1,d,phi),d*=m,phi*=m;
}
void MoLing_qwq(){
    n=read();m=read();
    ans=(qpow(m,n)+(n-1)*m)%p;
    v=getp(n-1);
    dfs(0,1,1);
    printf("%lld\n",ans*inv(n*(n-1)%p)%p);
}
int T;
int main(){
    T=read();p=read();
    while(T--)MoLing_qwq();
    return 0;
}

::::