试题描述 |
windy学会了一种游戏。 对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。 最开始windy把数字按顺序1,2,3,……,N写一排在纸上。 然后再在这一排下面写上它们对应的数字。 然后又在新的一排下面写上它们对应的数字。 如此反复,直到序列再次变为1,2,3,……,N。 如: 1 2 3 4 5 6 这时,我们就有若干排1到N的排列,上例中有7排。 |
输入格式 |
一个整数N |
输出格式 |
一个整数,可能的排数。 |
输入示例 |
输入样例一: 3 输入样例二: |
输出示例 |
输出样例一: 3 输出样例二: |
注释说明 |
30%的数据,满足 1 <= N <= 10 100%的数据,满足 1 <= N <= 1000 |
【分析】
对于原序列,每个数都有唯一且不同的数与之对应,这很像函数关系。
而对于对应序列,每个数的原像的是唯一的,所以序列中必定有若干个首尾相接的环,所有环中的数的总和为n。
又因为一个长度为m的环经过k*m次变换可以回到原来的状态,所以这个问题转化成了求若干个和为n的数的最小公倍数有多少种。
再因为若干个数的LCM是这若干个数中出现过的质因数中最高幂的乘积,而质数幂都是不同的,所以这个问题最后转化成了完全背包问题...
注意这里不足n的话可以用1补齐,任何数乘1都还是原数,这里也相当于背包可以不装满。
【代码】
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n, len=1; 5 long long ans; 6 long long a[1020], dp[1020]; 7 int pr[200]={0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 8 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 9 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 10 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 11 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 12 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 13 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 14 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 15 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 16 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 17 991, 997};//偷懒打了个质数表 18 19 int main() { 20 cin >> n; 21 dp[0]=1; 22 for (int i=1;i<=168;++i) 23 for (int j=n;j>=pr[i];--j) 24 for (int k=pr[i];k<=j;k*=pr[i]) 25 dp[j]+=dp[j-k]; 26 for (int i=0;i<=n;++i) 27 ans+=dp[i]; 28 cout << ans << endl; 29 }
时间: 2024-12-15 03:10:02