[loj3284]Exercise

对于一个排列$p_{i}$,假设循环长度依次为$x_{1},x_{2},...,x_{m}$,那么所需步数即${\rm lcm}_{i=1}^{m}x_{i}$

由于是乘积,因此可以枚举素数$p$,并统计其的次数(注意这是对$\varphi(M)=M-1$取模)

类似于$E(X)=\sum_{i\ge 1}P(X\ge i)$,定义$f(k)$表示满足$\exists k\mid x_{i}$的排列数,次数即$\sum_{\alpha\ge 1}f(p^{\alpha})$

关于$f(k)$,考虑总排列数为$n!$,并去掉$\forall 1\le i\le m,k\not\mid x_{i}$的排列数即为所求

令$dp_{i}$表示$n=i$且要求$\forall 1\le j\le m,k\not\mid x_{j}$时的方案数,同样考虑总排列数为$i!$,并去掉$\exists k\mid x_{j}$的排列数即为所求,后者去枚举$\sum_{k\mid x_{j}}x_{j}$,显然剩下的部分即为$dp_{i-\sum_{k\mid x_{j}}x_{j}}$

由此,转移即
$$
dp_{i}=i!-\sum_{1\le j\le \lfloor\frac{i}{k}\rfloor}{i\choose jk}g_{j}dp_{i-jk}
$$
其中$g_{i}$表示$n=ik$且要求$\forall 1\le j\le m,k\mid x_{j}$时的方案数,枚举$n$​所在循环长度,转移即
$$
g_{i}=\sum_{1\le j\le i}{ik-1\choose jk-1}(jk-1)!g_{i-j}
$$
显然计算$g_{i}$的复杂度为$o(\frac{n^{2}}{k^{2}})$,同时由于只需要求$dp_{n}$,根据转移只关心于$i\equiv n(mod\ k)$的$dp_{i}$,因此求$dp_{i}$的复杂度同样为$o(\frac{n^{2}}{k^{2}})$,也即求$f(k)$的复杂度为$o(\frac{n^{2}}{k^{2}})$

而$k$显然$\in [1,n]$且不重复,因此复杂度为$o(\sum_{i=1}^{n}\frac{n^{2}}{i^{2}})$,提出$n^{2}$后该式收敛于$\frac{\pi^{2}}{6}$

综上,总复杂度即为$o(n^{2})$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 7505
 4 #define ll long long
 5 int n,mod,ans,p[N],vis[N],fac[N],C[N][N],g[N],f[N];
 6 int qpow(int n,int m){
 7     int s=n,ans=1;
 8     while (m){
 9         if (m&1)ans=(ll)ans*s%mod;
10         s=(ll)s*s%mod;
11         m>>=1;
12     }
13     return ans;
14 }
15 int calc(int k){
16     memset(g,0,sizeof(g));
17     memset(f,0,sizeof(f));
18     g[0]=f[0]=1;
19     for(int i=1;i<=n/k;i++)
20         for(int j=1;j<=i;j++)g[i]=(g[i]+(ll)C[i*k-1][j*k-1]*fac[j*k-1]%(mod-1)*g[i-j])%(mod-1);
21     for(int i=0;i<=n;i++)
22         if (i%k==n%k){
23             f[i]=fac[i];
24             for(int j=1;j<=i/k;j++)f[i]=(f[i]-(ll)C[i][j*k]*g[j]%(mod-1)*f[i-j*k]%(mod-1)+mod-1)%(mod-1);
25         }
26     return (fac[n]-f[n]+mod-1)%(mod-1);
27 }
28 int main(){
29     for(int i=2;i<N;i++){
30         if (!vis[i])p[++p[0]]=i;
31         for(int j=1;(j<=p[0])&&(i*p[j]<N);j++){
32             vis[i*p[j]]=1;
33             if (i%p[j]==0)break;
34         }
35     }
36     scanf("%d%d",&n,&mod);
37     fac[0]=1;
38     for(int i=1;i<N;i++)fac[i]=(ll)i*fac[i-1]%(mod-1);
39     for(int i=0;i<N;i++){
40         C[i][0]=C[i][i]=1;
41         for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%(mod-1);
42     }
43     ans=1;
44     for(int i=1;i<=p[0];i++)
45         for(int j=p[i];j<=n;j*=p[i])ans=(ll)ans*qpow(p[i],calc(j))%mod;
46     printf("%d\n",ans);
47     return 0;
48 }
View Code

 

posted @ 2021-09-22 14:13  PYWBKTDA  阅读(39)  评论(0编辑  收藏  举报