BZOJ 1025 [SCOI2009]游戏
1025: [SCOI2009]游戏
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 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
3
【输入样例二】
10
Sample Output
【输出样例一】
3
【输出样例二】
16
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;}