zoukankan      html  css  js  c++  java
  • 1025: [SCOI2009]游戏

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2727  Solved: 1794
    [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,1 <= N <= 1000

    Output

      包含一个整数,可能的排数。

    Sample Input

    【输入样例一】
    3
    【输入样例二】
    10

    Sample Output

    【输出样例一】
    3
    【输出样例二】
    16
     
    这其实更像一道数学题。。。
    以题目中N=6为例:
    1 2 3 4 5 6 对应的关系为 1->2 2->3 3->1 4->5 5->4 6->6
    可以划分为(1,2,3) (4,5) (6) 三个循环节,模拟计算几组数据后发现都可以划分为这样的循环节
    循环节的长度之和正好等于N,(即:3+2+1=6),而一个可能的排数等于LCM(循环节长度),即所有循环节长度的公倍数+1
    因此问题转化为:和为N的一串数,求它们的最小公倍数,而这一串数可以继续分解成更小的数(即这一串数不是固定的),并继续求最小公倍数,所有可能的最小公倍数的总数,即为方案数
    如:
    一串数    最小公倍数
    6        6
    5 1       5
    4 2       4
    4 1 1       4
    3 3       3
    。。。。。。
    最终可以发现可行的最小公倍数是:1,2,3,4,5,6,这六种,因此答案为6
    而怎么求这一串数又成了问题,这里可以反过来思考,一个可行的最小公倍数需要满足的条件。
    最小公倍数一定是一个合数,而一个合数可以分解为多个质数的积,那么最小公倍数的一个因数就是多个质数相乘后的积,并且需要满足所有因数的和小于等于N
    因此可以得到最小公倍数Z=a1^b1 × a2^b2 × a3^b3 × ...(a为质数),如6=3^1 × 2^1
    等于N我们都知道,至于为什么可以小于N,假设N=6为例,其中一种可行的最小公倍数,6=3^1×2^1,而3+2≤6。
    因为作为这一串数:
    一串数    最小公倍数
    3 2 1       6
    可以补1这种情况。
    接下来就要用到动态规划,设f[i][j],i表示前i个质数,j表示因数的和,表示前i个质数,因数和小于等于N的情况总数
     
     
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 
     6 #define LL long long
     7 
     8 const int MAXN=10000;
     9 int cnt=0,prime[MAXN];
    10 int n;
    11 LL ans,f[200][1100];
    12 void Prime(int x)
    13 {
    14     bool mark[MAXN];
    15     for(int i=2;i<=x;i++)
    16     {
    17         if(!mark[i]) prime[++cnt]=i;
    18         for(int j=1;j<=cnt&&prime[j]*i<=x;j++)
    19         {
    20             mark[prime[j]*i]=1;
    21             if(i%prime[j]==0) break;
    22         }
    23     }
    24 }
    25 
    26 int main()
    27 {
    28     scanf("%d",&n);
    29     Prime(n);
    30     f[0][0]=1;
    31     for(int i=1;i<=cnt;i++)
    32         for(int j=0;j<=n;j++)
    33         {
    34             f[i][j]+=f[i-1][j];
    35             for(int k=prime[i];k<=j;k*=prime[i])
    36                 f[i][j]+=f[i-1][j-k];
    37         }
    38     for(int i=0;i<=n;i++)
    39         ans+=f[cnt][i];
    40     cout<<ans<<endl;
    41     return 0;
    42 }
  • 相关阅读:
    全局数据库名称/数据库实例/SID 的区别
    【转载】ORACLE 10G DBCA创建脚本实现手动创建数据库
    apue 20130328
    apue 20130323
    visual c++6.0
    C语言
    apue 20130322
    apue 20130324
    apue 20130325
    C语言里的字符串解析
  • 原文地址:https://www.cnblogs.com/InWILL/p/9265698.html
Copyright © 2011-2022 走看看