题意真纠结
题目大意:
规定一种1~N的对应关系(1~N的一种排列),按这种关系将顺序序列1~N反复变换,变回1~N所经过的变换次数+1 记为这种对应关系的排数,求排数有多少个【题解】
置换群的问题。对于每种对应关系,将其分解为循环节的形式,则变换次数为:各循环节长度的最小公倍数如 对应关系:1->2 2->3 3->1 4->5 5->4 6->6,转化后就是(1 2 3)(4 5)(6),排数 = lcm(3,2,1)+1 = 7
循环节总长为N,所以问题转化为:
将N分解成若干正整数之和,求它们最小公倍数可能的取值个数
我们发现,若一个分解出的数为a^p*b^q(a,b为质数),∵ a^p*b^q >= a^p+b^q ∴ 一定可以将这个数拆分为 a^p+b^q+x,lcm个数不会减少
因此,每个分解出的数都为 a^x (a为质数)不会漏解
设f[i][j]表示:用前i个质数组成j的方案数,那么f[i][j] = sigma( f[i-1][j-pri[i]^k] )
答案为 sigma(f[质数个数][0~N])
#include<stdio.h>
#include<stdlib.h>
long long f[505][1005]={0};
int pri[505]={0},hash[1005]={0};
int p=0;
void get_prime(int n)
{
int i,j;
for(i=2;i<=n;i++)
if(hash[i]==0)
{
pri[++p]=i;
for(j=i;j<=n;j+=i)
hash[j]=1;
}
}
int main()
{
long long ans=0;
int n,i,j,k;
scanf("%d",&n);
get_prime(n);
f[0][0]=1;
for(i=1;i<=p;i++)
{
for(j=0;j<=n;j++)
{
f[i][j]=f[i-1][j];
for(k=pri[i];j-k>=0;k*=pri[i])
f[i][j]+=f[i-1][j-k];
}
}
for(i=0;i<=n;i++)
ans+=f[p][i];
printf("%lld",ans);
return 0;
}