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
3
【输入样例二】
10
Sample Output
【输出样例一】
3
【输出样例二】
16
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 }