1025: [SCOI2009]游戏

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 。

 
 
看了题解才明白。。。首先要将问题转化一下,变成将n个数划分成几部分,每个部分看做一个环,然后我们要找的就是从环上的一点走k步,正好都回到了起点。。。所以我们可以将这个问题转化成几个数相加等于n,然后这几个数的最小公倍数。。。然后这样的组合的总数。。。
然后这里用一下贪心。。。用素数肯定要比合数更优。。。所以我们先找素数然后进行DP。。。
这里用F[i][j]表示前i个素数的和(也可以是素数的幂的和)在j以内的方案总数。。。
然后就可以得到F[i][j]=sum(F[i-1][j-p[i]^k)。。p[i]表示第i个素数。。。
 4 #include<iostream>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 #include<cstdio>
 9 #include<algorithm>
10 #include<string>
11 #include<map>
12 #include<queue>
13 #include<vector>
14 #include<set>
15 #define inf 1000000000
16 #define maxn 1000+5
17 #define maxm 1000+5
18 #define eps 1e-10
19 #define ll long long
20 #define for0(i,n) for(int i=0;i<=(n);i++)
21 #define for1(i,n) for(int i=1;i<=(n);i++)
22 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
23 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
24 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
25 using namespace std;
26 int p[maxn],tot;
27 ll f[maxn][maxn];
28 bool mark[maxn];
29 int read(){
30     int x=0,f=1;char ch=getchar();
31     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
32     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
33     return x*f;
34 }
35 int main(){
36     //freopen("input.txt","r",stdin);
37     //freopen("output.txt","w",stdout);
38     f[0][0]=1;
39     for(int i=2;i<=1000;i++){
40         if(!mark[i])p[++tot]=i;
41         for(int j=1;j<=tot&&i*p[j]<=1000;j++){
42             mark[i*p[j]]=1;
43             if(i%p[j]==0)break; 
44         }
45     }
46     int n=read();ll ans=0;
47     for1(i,tot){
48         for0(j,n)f[i][j]=f[i-1][j];
49         for(int j=p[i];j<=n;j*=p[i])
50         for0(k,n-j)
51         f[i][k+j]+=f[i-1][k];
52     }
53     for0(i,n)ans+=f[tot][i];
54     printf("%lld",ans);
55     return 0;
56 }
View Code

 

posted @ 2016-02-11 12:41  HTWX  阅读(124)  评论(0编辑  收藏  举报