[BZOJ 1025] [SCOI2009] 游戏 【DP】

题目链接:BZOJ - 1025

题目分析

显然的是,题目所要求的是所有置换的每个循环节长度最小公倍数的可能的种类数。

一个置换,可以看成是一个有向图,每个点的出度和入度都是1,这样整个图就是由若干个环构成,这些环的长度和为 n 。

因此,就是要求出和为 n 的正整数的最小公倍数的可能情况。

有一个性质:这些正整数中有合数存在的最小公倍数,都可以用全是质数的情况包含。

所以我们只要求出用质数组成的情况就可以了。我们要求的就是,若干个质数,它们的和小于等于 n,它们的最小公倍数情况。

先筛法求出 n 以内的所有素数。然后使用 DP:

f[i][j] 表示前 i 个素数之内,组成的和为 j ,LCM 的种类数。

f[i][j] = f[i - 1][j] + sigma(f[j - Prime[i]^k])

初始状态是 f[0][0] = 1

当一些质数的和不同的时候,它们的积一定不同。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int MaxN = 1000 + 5;

int n, Top;
int Prime[MaxN];

bool isPrime[MaxN];

typedef long long LL;
LL Ans;
LL f[MaxN][MaxN];

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) isPrime[i] = true;
	isPrime[1] = false; Top = 0;
	for (int i = 2; i <= n; ++i)
	{
		if (isPrime[i]) Prime[++Top] = i;
		for (int j = 1; j <= Top && i * Prime[j] <= n; ++j)
		{
			isPrime[i * Prime[j]] = false;
			if (i % Prime[j] == 0) break;
		}
	}
	f[0][0] = 1;
	for (int i = 1; i <= Top; ++i)
	{
		for (int j = 0; j <= n; ++j) f[i][j] = f[i - 1][j];
		for (int j = 0; j <= n; ++j)
			for (int k = Prime[i]; k <= n - j; k *= Prime[i])
				f[i][j + k] += f[i - 1][j];
	}
	Ans = 0;
	for (int i = 0; i <= n; ++i) Ans += f[Top][i];
	printf("%lld\n", Ans);
	return 0;
}

  

时间: 2024-12-28 08:05:14

[BZOJ 1025] [SCOI2009] 游戏 【DP】的相关文章

bzoj 1025 [SCOI2009]游戏 dp

题面 题目传送门 解法 显然,可以回到初始状态就意味着一定由若干个环组成 假设环的长度为\(l_i\) 那么,我们可以得到\(\sum l_i=n\) 不考虑自环的情况,那么\(\sum l_i≤n\) 将\(n\)以内的质因数全部筛出,强制每一次只取某一个质数的次幂,那么就可以解决重复计数的问题 时间复杂度:\(O(n^2)\) 代码 #include <bits/stdc++.h> #define int long long #define N 1010 using namespace s

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>

bzoj 1025 [SCOI2009]游戏(置换群,DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1025 [题意] 给定n,问1..n在不同的置换下变回原序列需要的不同排数有多少种. [思路] 对于一个置换,如果分解后的到的循环长度为 A1,A2,A3… 则答案为lcm(A1,A2…)的不同种数,即有多少个不同的lcm满足: A1+A2+A3+…=n lcm=lcm(A1,A2,A3…) 对于A[1..]的lcm, lcm=a1^max{p1}*a2^max{p2}.. 只考虑ma

BZOJ 1025 [SCOI2009]游戏

之前找LLJ大佬推荐水题的时候让我做这个,然后不出意料的我不会. 日常抄题解. 手玩几组数据发现它N个数可以分成多个组,每个组为一个循环,他们的LCM就是最后的层数. 预处理出n以内的所有质数,我们可以把n分解成p1^a1+p2^a2+p3^a3...不同的p之间的lcm数可以直接相乘,我们用dp递推地算答案,dp[i][j表示前i个质数和为j的lcm数,然后就可以DP了. 最后统计答案要把0~n的dp[p[0]][i]加起来,因为每个数可以单成一组. #include<cstdio> #in

BZOJ 1025 SCOI2009 游戏 动态规划

题目大意:给定n,定义一个置换的排数为1~n的循环经过这个置换最少T次(T>0)可以回到原来的序列 求所有可能的排数的数量 将一个置换分解为一些循环,那么这个置换的排数就是这些循环的长度的最小公倍数 于是对于一个数,我们验证这个数是否是排数的方式就是将这个数分解质因数,令x=p1^a1*p2^a2*...*pk^ak,若p1^a1+p2^a2+...+pk^ak<=n,则x就是可能的排数 分组背包即可 令f[i][j]表示用前i个质数,和为j能得出的数的数量 每组的物品是pi^1~pi^ai

bzoj1025: [SCOI2009]游戏(DP)

题目大意:将长度为n的排列作为1,2,3,...,n的置换,有可能置换x次之后,序列又回到了1,2,3,...,n,求所有可能的x的个数. 看见这种一脸懵逼的题第一要务当然是简化题意...我们可以发现,序列回到原状的次数就是每个循环的规模(即在循环中的数字个数)的lcm,而且因为有n个数,显然所有循环的规模之和就是n,那么问题就被简化成了a1+a2+a3+...+ak=n,求lcm(a1,a2,a3,...,an)的个数. 现在题意已经清楚多了,那咋写呢QAQ 我们把一个数分解质因数,p为质数,

【BZOJ 1025】 [SCOI2009]游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 1273  Solved: 805 [Submit][Status] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,--,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,2,3,--,N

BZOJ1025: [SCOI2009]游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2029  Solved: 1315[Submit][Status][Discuss] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,

SCOI2009游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1065  Solved: 673[Submit][Status] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,2,3,……,N.