bzoj1025 [SCOI2009]游戏 (背包)
1025: [SCOI2009]游戏
Submit: 2557 Solved: 1668
[Submit][Status][Discuss]
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想知道,对于所有可能的对应关系,有多少种可能的排数。
Input
包含一个整数N,1 <= N <= 1000
Output
包含一个整数,可能的排数。
一种对应关系对应的排数为所有循环节长度的LCM;
因此,排数可以写成 $∏prime[i]^{index[i]}$ ,符合此排数的序列最短长度为 $∑prime[i]^{index[i]}$ ;
如长度小于$n$只需用长度为$1$的循环节补全即可,于是就转化成了背包问题;
AC GET☆DAZE
↓代码
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<string> 5 #include<cstdio> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<map> 10 #include<set> 11 #define N 1039 12 #define mod 20070831 13 #define inf 0x3f3f3f3f 14 #define ll long long 15 using namespace std; 16 ll dp[1039][1039],tot,ans; 17 int main() 18 { 19 ll n,a,b,c; 20 scanf("%lld",&n); 21 dp[0][0]=1; 22 for(a=2;a<=n;a++) 23 { 24 for(b=2;b<a;b++) 25 { 26 if(a%b==0) 27 { 28 break; 29 } 30 } 31 if(b==a) 32 { 33 for(b=0;b<=n;b++) 34 { 35 dp[tot+1][b]+=dp[tot][b]; 36 for(c=a;b+c<=n;c*=a) 37 { 38 dp[tot+1][b+c]+=dp[tot][b]; 39 } 40 } 41 tot++; 42 } 43 } 44 for(int a=0;a<=n;a++) 45 { 46 ans+=dp[tot][a]; 47 } 48 printf("%lld",ans); 49 return 0; 50 }
散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ