Luogu

分析

显然一个置换的步数就是它所有环长的 $\operatorname{lcm}$。于是问题变为求有多少个数 $n$ 的某个拆分中所有数的 $\operatorname{lcm}$。

考虑 DP。设 $dp_{i,j}$ 表示 $i$ 拆成若干个最大质因子 $\leq p_j$ 且不为 $1$ 的数时的答案,不难得到转移
$$
dp_{i,j}=dp_{i,j-1}+\sum_{p_j\!^k\leq i}dp_{i-p_j\!^k,j-1}
$$
答案即为 $1+\sum_{i=1}^n dp_{n,|\mathrm{P}|}$。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
using namespace std;
typedef long long ll;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=10000+10,M=1250;

int n,mod;

int p[M],v[N],cnt=0;
void sieve(int n) {
    for (int i=2;i<=n;++i) {
        if (!v[i]) p[++cnt]=i;
        for (int j=1;j<=cnt&&i*p[j]<=n;++j) {
            v[i*p[j]]=1;
            if (i%p[j]==0) break;
        }
    }
}

int dp[N][M];

int main() {
    n=read(),mod=read(); sieve(n);
    for (int i=0;i<=cnt;++i) dp[0][i]=1;
    for (int i=1;i<=n;++i)
        for (int j=1;j<=cnt;++j) {
            dp[i][j]=dp[i][j-1];
            for (ll k=p[j];k<=i;k*=p[j])
                dp[i][j]=(dp[i][j]+dp[i-k][j-1]*k)%mod;
        }
    int ans=1;
    for (int i=1;i<=n;++i) ans=(ans+dp[i][cnt])%mod;
    printf("%d\n",ans);
    return 0;
}
最后修改:2020 年 08 月 07 日 07 : 53 PM