题解 P4709 【信息传递】
command_block · · 题解
题意 : 给出一个
求有多少个置换
总的来说就是
设长度为
能够发现不同大小的循环之间互不影响,我们每种大小分开考虑。
现有
设
则
中间是
其中,
复杂度
#include<algorithm>
#include<cstdio>
#include<vector>
#define ll long long
#define MaxN 100500
using namespace std;
const int mod=998244353;
ll powM(ll a,int t=mod-2){
ll ret=1;
while(t){
if (t&1)ret=ret*a%mod;
a=a*a%mod;t>>=1;
}return ret;
}
int d[MaxN],tn;
ll fac[MaxN],ifac[MaxN];
ll C(int n,int m)
{return fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
ll P(int r,int s)
{return fac[r-1]*powM(s,r-1)%mod;}
void Init(int n)
{
fac[0]=1;
for (int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
ifac[n]=powM(fac[n])%mod;
for (int i=n;i;i--)
ifac[i-1]=ifac[i]*i%mod;
for (int i=1;i<=n;i++)
if (n%i==0)d[++tn]=i;
}
int gcd(int a,int b)
{return !b ? a : gcd(b,a%b);}
ll dp[MaxN];
ll calc(int c,int s,int n)
{
dp[0]=1;
for (int i=1;i<=c;i++){
dp[i]=0;
for (int j=1;j<=tn&&d[j]<=i;j++){
int r=d[j];
if (gcd(n,r*s)==r)
dp[i]=(dp[i]+C(i-1,r-1)*P(r,s)%mod*dp[i-r])%mod;
}
}return dp[c];
}
bool vis[MaxN];
int n,p[MaxN],c[MaxN];
int main()
{
scanf("%d",&n);
Init(n);
for (int i=1;i<=n;i++)
scanf("%d",&p[i]);
for (int i=1;i<=n;i++)
if (!vis[i]){
int siz=0,u=i;
while(!vis[u])
{vis[u]=1;siz++;u=p[u];}
c[siz]++;
}
ll ans=1;
for (int i=1;i<=n;i++)
if (c[i])
ans=ans*calc(c[i],i,n)%mod;
printf("%lld",ans);
return 0;
}