zoukankan      html  css  js  c++  java
  • 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('
    ')
     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;}
  • 相关阅读:
    Design Thinking 设计思维
    SELECT小技巧
    网站架构
    代码生成器重构
    如何监控你的鼠标
    Asp.net超轻异步框架
    跨线程修改UI控件
    NPOI组件
    浅析Linux计算机工作机制
    VS2010单元测试
  • 原文地址:https://www.cnblogs.com/chxer/p/4659272.html
Copyright © 2011-2022 走看看