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)