很早之前看到过这道题,当时连置换是什么都不知道。。。
首先考虑置换 g g g中的某一个长为 S S S的循环环,学过群论的应该知道,在置换自乘 n n n次之后,这个循环会变为 g c d ( n , S ) gcd(n,S) gcd(n,S)个循环。
考虑将 t t t个长为 S S S的循环拼接成一个,使得若干次自乘之后这个循环断裂为 t t t个长为 S S S的循环。翻过任何一本群论教材就知道,最后在同一循环中的元素是那些只与初始下标 % S \%S %S的值有关,所以这一部分的方案数为 S t − 1 ( t − 1 ) ! S^{t-1}(t-1)! St−1(t−1)!,其实就是考虑一个圆排列。
所有长度为 S S S的循环显然可以放在一起处理。
考虑 e x p exp exp的组合意义,显然我们对于每个长度求出拿 t t t个该长度的串来拼接成一个的方案数的 E G F EGF EGF,设为 A ( x ) A(x) A(x),则拿出 c n t [ S ] cnt[S] cnt[S]个循环,拼接成若干个的方案数的生成函数为 exp ( A ( x ) ) \exp(A(x)) exp(A(x)),复杂度 O ( n log n ) O(n\log n) O(nlogn),而且不好卡满。
然而这个玩意可以直接 D P DP DP,复杂度 O ( n 4 3 ) O(n^{\frac{4}{3}}) O(n34),同样,几乎卡不满
代码(DP):
#include
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
return res;
}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}
inline int gcd(int a,int b){
#define ctz __builtin_ctz
int shift=ctz(a|b);
for(b>>=ctz(b);a;a-=b)if((a>>=ctz(a))<b)std::swap(a,b);
return b<<=shift;
}
cs int N=1e5+5;
int n;
int fac[N],ifac[N];
inline void init(){
fac[0]=fac[1]=ifac[0]=1;
for(int re i=2;i<=n;++i)fac[i]=mul(fac[i-1],i);
ifac[n]=power(fac[n],mod-2);
for(int re i=n-1;i;--i)ifac[i]=mul(ifac[i+1],i+1);
}
inline int C(int n,int m){return (n>=0&&m>=0&&n>=m)?mul(fac[n],mul(ifac[m],ifac[n-m])):0;}
std::vector<int> factor;
int to[N],cnt[N];
bool vis[N];
int dp[N],coef[N];
signed main(){
#ifdef zxyoi
freopen("message.in","r",stdin);
#endif
n=getint();init();
for(int re i=1;i<=n;++i)to[i]=getint();
for(int re i=1;i<=n;++i)if(!vis[i]){
int len=0,x=i;
while(!vis[x]){
vis[x]=true;
++len;x=to[x];
}
++cnt[len];
}
for(int re i=1;i*i<=n;++i)
if(n%i==0){
factor.push_back(i);
if(i*i!=n)factor.push_back(n/i);
}
std::sort(factor.begin(),factor.end());
int ans=1;
for(int re i=1;i<=n&&ans;++i)if(cnt[i]){
coef[1]=1;
for(int re j=2;j<=cnt[i];++j)coef[j]=mul(coef[j-1],mul(i,j-1));
memset(dp+1,0,sizeof(int)*cnt[i]);
dp[0]=1;
for(int re j=1;j<=cnt[i];++j){
for(int re t:factor){
if(t>j)break;
if(gcd(n,i*t)!=t)continue;
Inc(dp[j],mul(dp[j-t],mul(C(j-1,t-1),coef[t])));
}
}
ans=mul(ans,dp[cnt[i]]);
}
cout<<ans<<"\n";
return 0;
}
代码exp:
#include
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
inline int gcd(int a,int b){
#define ctz __builtin_ctz
int shift=ctz(a|b);
for(b>>=ctz(b);a;a-=b)if((a>>=ctz(a))<b)std::swap(a,b);
return b<<=shift;
}
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
return res;
}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}
cs int SIZE=1<<19|1,bit=19;
typedef std::vector<int> Poly;
int r[SIZE],*w[bit+1];
inline void init_NTT(){
for(int re i=1;i<=bit;++i)w[i]=new int[1<<i-1];
int wn=power(3,(mod-1)>>bit);
w[bit][0]=1;
for(int re i=1;i<(1<<bit-1);++i)w[bit][i]=mul(w[bit][i-1],wn);
for(int re i=bit-1;i;--i)
for(int re j=0;j<(1<<i-1);++j)w[i][j]=w[i+1][j<<1];
}
inline void NTT(Poly &A,int len,int typ){
for(int re i=0;i<len;++i)if(i<r[i])std::swap(A[i],A[r[i]]);
for(int re i=1,t=1;i<len;i<<=1,++t)
for(int re j=0;j<len;j+=i<<1)
for(int re k=0;k<i;++k){
int x=A[j+k],y=mul(A[j+k+i],w[t][k]);
A[j+k]=add(x,y),A[j+k+i]=dec(x,y);
}
if(typ==-1){
std::reverse(A.begin()+1,A.begin()+len);
for(int re i=0,inv=power(len,mod-2);i<len;++i)A[i]=mul(A[i],inv);
}
}
inline void init_rev(int len){
for(int re i=0;i<len;++i)r[i]=r[i>>1]>>1|((i&1)?len>>1:0);
}
int fac[SIZE],ifac[SIZE],inv[SIZE];
inline void init_inv(){
fac[0]=fac[1]=ifac[0]=ifac[1]=inv[0]=inv[1]=1;
for(int re i=2;i<SIZE;++i){
fac[i]=mul(fac[i-1],i);
inv[i]=mul(inv[mod%i],mod-mod/i);
ifac[i]=mul(ifac[i-1],inv[i]);
}
}
inline int C(int n,int m){return (n>=0&&m>=0&&n>=m)?mul(fac[n],mul(ifac[m],ifac[n-m])):0;}
inline Poly operator*(Poly a,Poly b){
int deg=a.size()+b.size()-1,l=1;
while(l<deg)l<<=1;init_rev(l);
a.resize(l);NTT(a,l,1);
b.resize(l);NTT(b,l,1);
for(int re i=0;i<l;++i)a[i]=mul(a[i],b[i]);
NTT(a,l,-1);a.resize(deg);
return a;
}
inline Poly Deriv(Poly a){
for(int re i=0;i+1<a.size();++i)a[i]=mul(a[i+1],i+1);
a.pop_back();return a;
}
inline Poly Integ(Poly a){
a.push_back(0);
for(int re i=a.size()-1;i;--i)a[i]=mul(a[i-1],inv[i]);
a[0]=0;return a;
}
inline Poly Inv(cs Poly &a,int lim){
Poly c,b(1,power(a[0],mod-2));
for(int re l=4;(l>>2)<lim;l<<=1){
init_rev(l);
c=a,c.resize(l>>1);
c.resize(l),NTT(c,l,1);
b.resize(l),NTT(b,l,1);
for(int re i=0;i<l;++i)b[i]=mul(b[i],dec(2,mul(b[i],c[i])));
NTT(b,l,-1);b.resize(l>>1);
}b.resize(lim);
return b;
}
inline Poly Ln(Poly a,int lim){
a=Integ(Deriv(a)*Inv(a,lim));
a.resize(lim);
return a;
}
inline Poly Exp(cs Poly &a){
Poly c,b(1,1);int n=a.size();
for(int re i=2;(i>>1)<n;i<<=1){
c=Ln(b,i);
for(int re j=0;j<i;++j)c[j]=dec(j<n?a[j]:0,c[j]);
c[0]=add(c[0],1);
b=b*c;b.resize(i);
}b.resize(n);
return b;
}
cs int N=1e5+5;
int n;
std::vector<int> factor;
int to[N],cnt[N];
bool vis[N];
Poly f,g;
signed main(){
init_NTT();
init_inv();
#ifdef zxyoi
freopen("message.in","r",stdin);
#endif
n=getint();
for(int re i=1;i<=n;++i)to[i]=getint();
for(int re i=1;i<=n;++i)if(!vis[i]){
int len=0,x=i;
while(!vis[x]){
vis[x]=true;
++len;x=to[x];
}
++cnt[len];
}
for(int re i=1;i*i<=n;++i)
if(n%i==0){
factor.push_back(i);
if(i*i!=n)factor.push_back(n/i);
}
std::sort(factor.begin(),factor.end());
int ans=1;
for(int re i=1;i<=n&&ans;++i)if(cnt[i]){
f=Poly(cnt[i]+1,0);
for(int re j:factor){
if(j>cnt[i])break;
if(gcd(j*i,n)!=j)continue;
f[j]=power(i,j-1,inv[j]);
}
g=Exp(f);
ans=mul(ans,mul(g[cnt[i]],fac[cnt[i]]));
}
cout<<ans<<"\n";
return 0;
}