首先,不难想到的是,最后的排数应该是各个独立循环节的lcm。
并且对于每一个独立的循环节,若其长度为x,那么这个循环中必定有x个不重复的数字。
然而总的数字个数为n,那么显然各个循环节的长度和为n
也就是:
len1+len2+len3...+lenk=n
求:
lcm(len1,len2,len3...,lenk)有多少种
显然若其中有几个len为1,并不影响结果,于是条件进一步为:
len1+len2+len3...+lenk<=n
然后真正巧妙的东西来了。
设lcm=p1^a1*p2^a2*p3^a2..pk^ak (此处k和上面k无关)
*各质因数的次数来源于len1...lenk中的对应次数最大值
然而我们需要的只是让lcm<=n
如何做到?充要条件是p1^a1+p2^a2...+pk^ak<=n
为什么呢?
我们让lcm<=n合法,只要设法构造出一组len1...lenk(假设已除去1)即可
然后我们反过来,我们只要让len1...lenk这样的构造合法,lcm<=n也就成立
根据之前*处,显然对于p1^a1所在的b1..pk^ak所在的bk
b1>=p1^a1,b2>=p2^a2... bk>=pk^ak
我们并不要求所有b1...bk都满足b1+...+bk<=n,那么只要其最小值<=n,构造就是合法的
然后就变成了背包问题辣,不过是第k件物品有pk^1..pk^ak共ak种权值罢了
-----------------------------------------------------------------------------------------------------------------------------
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1010;
ll pr[N],tot=0,n;
bool np[N];
ll f[2][N];
void Pre(){
for(int i=2;i<=N;i++){
if(!np[i]) pr[++tot]=i;
for(int j=1;j<=tot&&pr[j]*i<=N;j++){
np[i*pr[j]]=1;
if (!(i%pr[j])) break;
}
}
}
int main(){
// freopen("1025.in","r",stdin);
// freopen("1025.out","w",stdout);
Pre(); f[0][0]=1;
scanf("%lld",&n);
for(int i=1;i<=tot;i++){
memset(f[i&1],0,sizeof(f[i&1]));
for(int j=0;j<=n;j++){
f[i&1][j]=f[(i+1)&1][j];
for(int k=pr[i];k<=j;k*=pr[i])
f[i&1][j]+=f[(i+1)&1][j-k];
}
}ll ans=0;
for(int i=0;i<=n;i++) ans+=f[tot&1][i];
printf("%lld\n",ans);
return 0;
}