BZOJ 1025: [SCOI2009]游戏( 背包dp )
显然题目要求长度为n的置换中各个循环长度的lcm有多少种情况.
判断一个数m是否是满足题意的lcm. m = ∏ piai, 当∑piai ≤ n时是满足题意的. 最简单我们令循环长度分别为piai,不足n的话,我们令其他循环长度为1, 补到=n为止. 这样它们的lcm显然是=m的.
然后就是一个背包了...dp(i, j) = dp(i - 1, j) + ∑1≤t≤adp( i - 1, j - pt ) 表示前i个质数, 和为j有多少中方案
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1009; ll dp[2][maxn]; int prime[maxn], N = 0, n; bool check[maxn]; void init() { memset(check, 0, sizeof check); for(int i = 2; i <= n; i++) { if(!check[i]) prime[N++] = i; for(int j = 0; j < N && i * prime[j] <= n; j++) { check[i * prime[j]] = true; if(i % prime[j] == 0) break; } } } int main() { cin >> n; init(); int c = 0, p = 1; memset(dp[c], 0, sizeof dp[c]); dp[c][0] = 1; for(int i = 0; i < N; i++) { swap(c, p); memcpy(dp[c], dp[p], sizeof dp[c]); for(int t = prime[i]; t <= n; t *= prime[i]) for(int j = t; j <= n; j++) dp[c][j] += dp[p][j - t]; } ll ans = 0; for(int i = 0; i <= n; i++) ans += dp[c][i]; cout << ans << endl; return 0; }
1025: [SCOI2009]游戏
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1558 Solved: 977
[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。
Output
包含一个整数,可能的排数。
Sample Input
【输入样例一】
3
【输入样例二】
10
3
【输入样例二】
10
Sample Output
【输出样例一】
3
【输出样例二】
16
3
【输出样例二】
16
HINT
【数据规模和约定】
100%的数据,满足 1 <= N <= 1000 。
Source