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

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 }

 

posted @ 2019-03-25 15:47  于丰林  阅读(157)  评论(0编辑  收藏  举报