BZOJ 1025: [SCOI2009]游戏( 背包dp )

显然题目要求长度为n的置换中各个循环长度的lcm有多少种情况.

判断一个数m是否是满足题意的lcm. m = ∏ piai, 当∑pia≤ n时是满足题意的. 最简单我们令循环长度分别为piai,不足n的话,我们令其他循环长度为1, 补到=n为止. 这样它们的lcm显然是=m的.

然后就是一个背包了...dp(i, j) = dp(i - 1, j) + ∑1≤t≤adp( i - 1, j - p) 表示前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 MB
Submit: 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

Sample Output

【输出样例一】
3
【输出样例二】
16

HINT

 

【数据规模和约定】

100%的数据,满足 1 <= N <= 1000 。

 

Source

 

 

posted @ 2015-08-14 17:14  JSZX11556  阅读(133)  评论(0编辑  收藏