zoukankan      html  css  js  c++  java
  • 题目大意:给定一个序列,序列中的数两两不同,每一步进行两种操作,压栈和弹栈,问可能得到多少序列,输出总数。

    n<=1000

    考虑到每一次只有两种操作,并且不合法的情况就是弹栈次数多余压栈次数,这个就和括号匹配是一个原理,很显然就是卡特兰数了。

    卡特兰数的递推公式:C(2n,n)/(n+1),根据我们的常识判断,当n达到1000时,这个数已经远远超过了LL的范围,所以我们考虑高精,但是如果是每一次都乘并更新进位的话,那么恭喜你:时间空间两开花

    那么我们先从C(2n,n)上下手,(2n)!/n!/n!,这就是从n+1乘到2n除以1乘到n,那么由于我们知道除完之后得到的一定是整数,所以除数一定含有被除数的所有质因子,并且比被除数多,我们就可以考虑质因数分解。

    我们利用线性筛筛出每一个数的最小质因子,将其分解,并记录每一个质因子出现了多少次,遇到一个新的数就不断将其拆分直到为1为止,最后我们利用高精度乘法将他们乘到一起即可。

    最后,附上本题代码:

     1 #include<cstdio>
     2 #define maxn 4000
     3 #define LL long long
     4 using namespace std;
     5 
     6 LL n,ans[maxn+5],prime[maxn+5],cnt;
     7 LL min_prime[maxn+5],cou_prime[maxn+5];
     8 bool vis[maxn+5],ok;
     9 
    10 int main()
    11 {
    12     scanf("%lld",&n);
    13     for(int i=2; i<=n; i++)
    14     {
    15         if(vis[i]==0)
    16         {
    17             prime[++cnt]=i;
    18             min_prime[i]=i;
    19         }
    20         LL temp=i;
    21         while(min_prime[temp]!=temp)
    22         {
    23             cou_prime[min_prime[temp]]--;
    24             temp/=min_prime[temp];
    25         }
    26         cou_prime[min_prime[temp]]--;
    27         for(int j=1; j<=cnt&&i*prime[j]<=n*2; j++)
    28         {
    29             vis[i*prime[j]]=1;
    30             min_prime[i*prime[j]]=prime[j];
    31             if(i%prime[j]==0)
    32             {
    33                 break;
    34             }
    35         }
    36     }
    37     /*for(int i=1;i<=n;i++)
    38     {
    39         printf("%lld",cou_prime[i]);
    40     }*/
    41     for(int i=n+2; i<=n*2; i++)
    42     {
    43         if(vis[i]==0)
    44         {
    45             prime[++cnt]=i;
    46             min_prime[i]=i;
    47         }
    48         LL temp=i;
    49         while(min_prime[temp]!=temp)
    50         {
    51             cou_prime[min_prime[temp]]++;
    52             temp/=min_prime[temp];
    53         }
    54         cou_prime[min_prime[temp]]++;
    55         for(int j=1; j<=cnt&&i*prime[j]<=n*2; j++)
    56         {
    57             vis[i*prime[j]]=1;
    58             min_prime[i*prime[j]]=prime[j];
    59             if(i%prime[j]==0)
    60             {
    61                 break;
    62             }
    63         }
    64     }
    65     /*for(int i=1; i<=n*2; i++)
    66     {
    67         printf("%lld",cou_prime[i]);
    68     }*/
    69     ans[1]=1;
    70     for(int i=1; i<=n*2; i++)
    71     {
    72         for(int j=1; j<=cou_prime[i]; j++)
    73         {
    74             for(int k=1; k<=2000; k++)
    75             {
    76                 ans[k]*=i;
    77             }
    78             for(int k=1; k<=2000; k++)
    79             {
    80                 ans[k+1]+=ans[k]/10;
    81                 ans[k]%=10;
    82             }
    83         }
    84     }
    85     for(int i=2000; i>=1; i--)
    86     {
    87         if(ans[i]!=0)
    88         {
    89             ok=1;
    90         }
    91         if(ok==1)
    92         {
    93             printf("%lld",ans[i]);
    94         }
    95     }
    96     return 0;
    97 }
  • 相关阅读:
    支持向量机(二)
    kafka partiton迁移方法与原理
    park和unpark
    Replicated State Machine和WAL
    thrift源码分析
    thrift使用和源码分析
    kafka源码环境搭建
    kafka指定partiton生产
    gradle构建scala
    kafka consumer代码梳理
  • 原文地址:https://www.cnblogs.com/yufenglin/p/10594156.html
Copyright © 2011-2022 走看看