我觉得很有思维含量的一道题
首先根据置换的知识,
每一个置换都可以表示成若干不想交的循环的乘积
所有循环的规模A1+A2+……AK=n
显然要求可能的排数,就是问n拆分成若干个数其可能的最小公倍数的个数
考虑到任意一个数大于1的自然数X一定能这样分解 令p为质数数组
X=p1^m1*p2^m2*…ph*mh
判断X是否可行我们可以想办法构造{Ah}使得其最小公倍数为X
显然{Ah}中pi的指数的最大值是mi
所以,和最小的满足最小公倍数为X的{Ah}是A1=p1^m1 A2=p2^m2 ……Ah=ph*mh(显然每个数都大于等于2)
如果满足A1+A2+……Ah<=n 则X为可行解
因为当A1+A2+……Ah=n 那显然存在可行解
而如果A1+A2+……Ah<n 我们一定可以令Ah+1~Ak全为1,这样最小公倍数不变,也满足了A1+A2+……AK=n
考虑到每一个X都对应唯一的分解质因式,每个分解质因式对应唯一的x
所以我们穷举上述的构造方案所得的最大公倍数一定不遗漏且唯一;
所以,寻找所有可行的X就转化为寻找满足下面条件的方案数
A1+A2+……Ah<=n
Ai=pi*mi (mi是不确定)
这样我们可用类似背包的方法解决
设f[i,j]表示用前i个质数,对应Ai和为j的方案数
显然f[i,j]=f[i-1,j](这个质数可以不用)+signma(f[i-1,j-p[i]^k]) (j-p[i]^k>=0) (穷举Ai的可能性);
初始f[0,0]=1;
最后答案就是signma(f[t,i]) 0<=i<=n;
1 var a:array[0..200] of longint; 2 f:array[0..200,0..1010] of int64; 3 i,j,n,t,k:longint; 4 ch:boolean; 5 ans:int64; 6 7 begin 8 readln(n); 9 for i:=2 to n do 10 begin 11 ch:=true; 12 for j:=2 to trunc(sqrt(i)) do //质数表 13 if i mod j=0 then 14 begin 15 ch:=false; 16 break; 17 end; 18 if ch then 19 begin 20 inc(t); 21 a[t]:=i; 22 end; 23 end; 24 f[0,0]:=1; 25 for i:=1 to t do 26 for j:=0 to n do 27 begin 28 f[i,j]:=f[i-1,j]; 29 k:=a[i]; 30 while j-k>=0 do 31 begin 32 f[i,j]:=f[i,j]+f[i-1,j-k]; 33 k:=k*a[i]; 34 end; 35 end; 36 ans:=0; 37 for i:=0 to n do 38 ans:=ans+f[t,i]; 39 writeln(ans); 40 end.