BZOJ1025: [SCOI2009]游戏

12 篇文章 0 订阅
9 篇文章 0 订阅

http://www.lydsy.com/JudgeOnline/problem.php?id=1025

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想知道,对于所有可能的对应关系,有多少种可能的排数。

1 <= N <= 1000 。



首先一个对应关系的排数就是一个置换里面每一个联通块大小的LCM,所以问题转化成了:

把一个数N,拆分成若干个数A1,A2,A3....,使得A1+A2+A3..=N

求LCM{A1,A2,A3..}的不同数值个数。

若一个数A=a1^p1*a2^p2... 那这个数是划不来的,因为LCM=a1^max{p1}*a2^max{p2}...

A=a1^p1*a2^p2,若这里面的p1,p2都是最大的,那对LCM的贡献和 B=a1^p1, C=a2^p2 是一样的。

但是B+C<B*C=A,所以把A分解成B和C是完全更优的。

所以一个数肯定是一个单一质数的幂次方。

所以现在的问题又简化成了这样:

Ax=ax^px

A1+A2+A3..≤N


a1,a2,a3都是定值,就是小于N的质数。

求满足条件的{p}数列的方法总数。


然后很神奇的转化成了背包的问题。

有点像什么今明的设呢懂洗。

ax只能选一次

所以对于每个Ax=ax^p 分别来做一遍再把两个数组合起来。。什么的。

f[i]表示A1+A2+..=i的时候的方法数

f[i]+=f[i-Ai]


#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
typedef long long LL;
const int MAX_N=1050;
int prime[MAX_N],top;
int n;
void Prep(){
	rep(i,2,n){
		bool flag=0;
		for (int j=2;j*j<=i;++j) if (i%j==0){flag=true;break;}
		if (!flag) prime[++top]=i;
		}
}
LL f[MAX_N][MAX_N];
void DP(){
	rep(i,0,top) f[i][0]=1;
	rep(i,1,top){
		for (int j=prime[i];j<=n;j*=prime[i])
			per(k,n,j) f[i][k]+=f[i-1][k-j];
		rep(j,1,n) f[i][j]+=f[i-1][j];
		}
	LL res=0;
	rep(i,0,n) res+=f[top][i];
	printf("%lld\n",res);
}
int main(){
	scanf("%d",&n);
	Prep();
	DP();
}



注重把实际问题转化为数学模型!通过数学模型推导分析!这相当重要!


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值