[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.