BZOJ 1025 [SCOI2009]游戏

1025: [SCOI2009]游戏

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 1533  Solved: 964
[Submit][Status][Discuss]

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 。

 

Source

题解:

如果一些数的最小公倍数为Z,而Z=x1^p1*x2^p2...xm^pm的话,当它们为x1^p1,x2^p2...时,它们的和最小。我们尝试尽量把这个最小化,因为达到最小化后,如果和小于等于N(不足可添1),就可以判定Z可以取到了。然后,可以发现,我们可以通过枚举xi^pi(质因数和其对应指数)来枚举Z(而且这样肯定不会重复),限制条件是和小于等于N。那么用dp[k][s]表示用前k个质数,枚举出来的所有Z的那个最小和为s的情况数。头疼,就写个记忆化好了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cstring>
 7 #define PAU putchar(' ')
 8 #define ENT putchar('\n')
 9 using namespace std;
10 const int maxn=200+10,maxm=1000+10,maxp=10000+10;
11 long long dp[maxn][maxm];int P[maxn],sz,n;bool pri[maxp];
12 void makepri(int n){
13     int lim=sqrt(n);memset(pri,true,sizeof(pri));
14     for(int i=2;i<=lim;i++)if(pri[i])for(int j=i*i;j<=n;j+=i)pri[j]=false;
15     for(int i=2;i<=n;i++)if(pri[i])P[++sz]=i;return;
16 }
17 long long calc(int k,int s){
18     if(dp[k][s]>=0)return dp[k][s];if(!k)return dp[k][s]=1;
19     dp[k][s]=calc(k-1,s);
20     for(int tmp=P[k];tmp<=s;tmp*=P[k])dp[k][s]+=calc(k-1,s-tmp);
21     return dp[k][s];
22 }
23 inline int read(){
24     int x=0,sig=1;char ch=getchar();
25     while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();}
26     while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
27     return x*=sig;
28 }
29 inline void write(long long x){
30     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
31     int len=0;long long buf[20];while(x)buf[len++]=x%10,x/=10;
32     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
33 }
34 void init(){
35     n=read();
36     makepri(n);memset(dp,-1,sizeof(dp));
37     write(calc(sz,n));
38     return;
39 }
40 void work(){
41     return;
42 }
43 void print(){
44     return;
45 }
46 int main(){init();work();print();return 0;}

 

你可能感兴趣的:(ZOJ)