题目大意
windywindywindy学会了一种游戏。 对于111到NNN这N个数字,都有唯一且不同的111到NNN的数字与之对应。 最开始windywindywindy把数字按顺序1,2,3,……,N1,2,3,……,N1,2,3,……,N写一排在纸上。 然后再在这一排下面写上它们对应的数字。 然后又在新的一排下面写上它们对应的数字。 如此反复,直到序列再次变为1,2,3,……,N1,2,3,……,N1,2,3,……,N。 这时,我们就有若干排1到N的排列。 现在windywindywindy想知道,对于所有可能的对应关系,有多少种可能的排数。
题目解析
仔细分析数字的对应关系,可以发现这 NNN 个数会组成很多个环。设有 KKK 个环,每 个 环 的 长 度 为 l[i]l[i]l[i] , 明 显 的 , 他 们 最 终 还 原 为 原 序 列 的 排 数 为LCM(l[1],l[2],l[3],...,l[k])LCM(l[1],l[2],l[3],...,l[k])LCM(l[1],l[2],l[3],...,l[k])。设这个排数为 AAA,不妨把 AAA 分解质因数,令A=P1cA=P_1^cA=P1c1^11∗P1c*P_1^c∗P1c2^22∗...∗*...*∗...∗PkcP_k^cPkck^kk
由于知道互质的数的lcmlcmlcm最大,所以令序列lll互质,即全部为质数,所以用到DPDPDP。
设f[i,j]f[i,j]f[i,j]表示前 iii 个质数,总和为 jjj 的方案数,那么 f[i,j]=∑f[i−1,j−prime[i]k]f[i,j]=∑f[i-1,j-prime[i]^k]f[i,j]=∑f[i−1,j−prime[i]k],先把 nnn 以内的质数筛出来,再求一遍 DPDPDP,答案就是∑f[质数总数,i]∑f[质数总数,i]∑f[质数总数,i]。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,pi,ans;
ll p[1005],f[1005][1005];
bool vis[1005];
int main()
{
cin>>n;
for(int i=2;i<=n;i++)
if(!vis[i])
{
p[++pi]=i;
for(int j=i*2;j<=n;j+=i)
vis[j]=1;
}
f[0][0]=1;
for(int i=1;i<=pi;i++)
{
for(int j=0;j<=n;j++) f[i][j]=f[i-1][j];
for(int j=p[i];j<=n;j*=p[i])
for(int k=j;k<=n;k++)
f[i][k]+=f[i-1][k-j];
}
for(int i=0;i<=n;i++) ans+=f[pi][i];
cout<<ans;
}