我觉得很有思维含量的一道题

首先根据置换的知识,

每一个置换都可以表示成若干不想交的循环的乘积

所有循环的规模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.
View Code

 

posted on 2014-07-19 21:39  acphile  阅读(558)  评论(0编辑  收藏