1038. 【SCOI2009】游戏 (Standard IO)

18 篇文章 1 订阅

 

Time Limits: 1000 ms  Memory Limits: 65536 KB  Detailed Limits  

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

 

12 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

Sample Output

3

Data Constraint

Hint

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

Source / Author: 四川2009省选第1试第2题

 

对于一个原序列和转化序列。我们可以处理每一个数字变化多少次可以到原来的位置。

每一个数字变化多少次可以到原来的位置等价于按照转换序列的意思连一下边 , 再求所有环。

设其中一环上节点数l, 这个环内的所有数变化l次即可回到原来位置。可以手玩得出。

 

然后我们得到了所有环的节点数l1 、l2、l3、......在这个转换序列的意义下  , 原序列显然需变化[l1 ,l2,l3...,lk]次才可还原序列。

 

可是我们不能暴力求出所有的转换序列 , 但是我们可以得出一个结论 : l1 + l2 + ... lk = n 。显然。

我们把1~n内的质数筛出,问题转化成为 :有一些质数(假装1也是) , ·在里面选取u个 , 使他们的和为n , 问取出的数lcm有几种。

我们可以设f[i][j]为到第i个质数 , 和为j的lcm方案数 。 f[i][j] += f[i-1][j - pri[j]^k],可是当pri[j]是1,麻烦就大了,因此我们钦定把l 为 1的都删除。

 

然后题目转化为:l1 + l2 + ... lk <=n (不足n补1即可)

有一些质数(1不是) , ·在里面选取u个 , 使他们的和为n , 问取出的数lcm有几种。

这样就可以dp了。

为什么可以这么DP ? 因为pri[j] 是质数 , 改变pri[j]的次数 , 再和前i-1个质数搞在一起,lcm显然都是新的。

答案是∑f[质数总数][i]。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mcy(a,b) memcpy(a,b,sizeof(a))
#define ll long long
#define re register

#define inf 2000000000
#define maxn 110
#define N 10001
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;

ll n,f[N],ans,pri[N],num;

ll ss(ll x)
{
	for(ll j=2;j*j<=x;j++) if(x%j==0) return 0;
	return 1;
}

void findpri()
{
	for(ll i=2;i<=n;i++) if(ss(i)) pri[++num] = i;
}




void dp()
{
	f[0]=1;
	for(ll i=1;i<=num;i++)
		for(ll j=n;j>=0;j--)
			for(ll tmp=pri[i];tmp<=j;tmp = tmp * pri[i])  
				f[j] += f[j - tmp];
}

int main()
{
	open("game");
	scanf("%lld",&n);
	findpri();
	dp();
	for(ll i=0;i<=n;i++)ans = ans + f[i];
	printf("%lld",ans);
	return 0;
}

O(质数个数*n*log n)

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值