[BZOJ1025] [SCOI2009]游戏 解题报告

Description

  windy学会了一种游戏。对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。最开始windy把数字按顺序1,2,3,……,N写一排在纸上。然后再在这一排下面写上它们对应的数字。然后又在新的一排下面写上它们对应的数字。如此反复,直到序列再次变为1,2,3,……,N。 如: 1 2 3 4 5 6 对应的关系为 1->2 2->3 3->1 4->5 5->4 6->6 windy的操作如下 1 2 3 4 5 6 2 3 1 5 4 6 3 1 2 4 5 6 1 2 3 5 4 6 2 3 1 4 5 6 3 1 2 5 4 6 1 2 3 4 5 6 这时,我们就有若干排1到N的排列,上例中有7排。现在windy想知道,对于所有可能的对应关系,有多少种可能的排数。

 

  题意是让我们求回归到原序列的置换次数,也就是对于这个置换的每一个循环大小的最小公倍数

  如(123)(45)(6)

  对于第一个循环回归需要3x次(x代表任意自然数),第二个循环需要2x次,第三个循环需要x次

  显然对于这样的置换答案是6次

  有多少种可能的排数,也就是这个最小公倍数有多少种可能..?

  看起来比较奇怪的问题...

  我们用一个序列来表示最小公倍数

  2  3   5   7   11...997

  x1 x2  x3  x4  x5...x168

  最小公倍数就是2^x1*3^x2*5^x3...997^x168(说白了就是质因数分解>w<)

  对于每一个循环,它的大小质因数分解之后对于每个质因子的系数都<=上面的序列

  然后原问题就是满足题意的x1,x2..x168有多少种

  我们来考虑怎样才会不满足题意...

  首先x1,x2..x168再小也无所谓,因为就算全为0也是满足题意的,剩下的都可以用1来补全

  显然对于这些x最小的n就是2^x1+3^x2...+997^x168

  因为一旦2出现了x1次,说明一定有一个循环的个数中含有2^x1这个因子,我们令其中一个等于这个

  为了使n最小化,其它都不含2这个因子

  另外加法比乘法代价小这个显然...

  也就是说对于x序列的限制也就是2^x1+3^x2...997^x168<=n

  非常眼熟...非常简单的01背包...

  

 1 /**************************************************************
 2     Problem: 1025
 3     User: mjy0724
 4     Language: Pascal
 5     Result: Accepted
 6     Time:112 ms
 7     Memory:8236 kb
 8 ****************************************************************/
 9  
10 program bzoj1025;
11 const maxn=1010;
12 var n,ans:int64;
13     i,j,k:longint;
14     p:array[-1..maxn]of int64;
15     f:array[-1..maxn,-1..maxn]of int64;
16     vis:array[-1..maxn]of boolean;
17  
18 procedure Euler;
19 var i,j:longint;
20 begin
21     fillchar(vis,sizeof(vis),true);
22     p[0]:=0;
23     for i:=2 to n do
24     begin
25         if vis[i] then
26         begin
27             inc(p[0]);
28             p[p[0]]:=i;
29         end;
30         for j:=1 to p[0] do
31         begin
32             if i*p[j]>n then break;
33             vis[i*p[j]]:=false;
34             if i mod p[j]=0 then break;
35         end;
36     end;
37 end;
38  
39 begin
40     readln(n);
41     Euler;
42     fillchar(f,sizeof(f),0);
43     f[0,0]:=1;
44     for i:=1 to p[0] do
45         for j:=0 to n do
46         begin
47                         f[i][j]:=f[i-1][j];
48             k:=p[i];
49             while k<=j do
50             begin
51                 inc(f[i,j],f[i-1,j-k]);
52                 k:=k*p[i];
53             end;
54         end;
55     ans:=0;
56     for i:=0 to n do inc(ans,f[p[0],i]);
57     writeln(ans);
58 end.

 

posted @ 2015-04-13 12:41  mjy0724  阅读(274)  评论(0编辑  收藏  举报