【bzoj1485】[HNOI2009]有趣的数列
Description
我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件:
(1)它是从1到2n共2n个整数的一个排列{ai};
(2)所有的奇数项满足a1<a3<…<a2n-1,所有的偶数项满足a2<a4<…<a2n;
(3)任意相邻的两项a2i-1与a2i(1≤i≤n)满足奇数项小于偶数项,即:a2i-1<a2i。
现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列。因为最后的答案可能很大,所以只要求输出答案 mod P的值。
Input
输入文件只包含用空格隔开的两个整数n和P。输入数据保证,50%的数据满足n≤1000,100%的数据满足n≤1000000且P≤1000000000。
Output
仅含一个整数,表示不同的长度为2n的有趣的数列个数mod P的值。
Sample Input
3 10
Sample Output
5
对应的5个有趣的数列分别为(1,2,3,4,5,6),(1,2,3,5,4,6),(1,3,2,4,5,6),(1,3,2,5,4,6),(1,4,2,5,3,6)。
对应的5个有趣的数列分别为(1,2,3,4,5,6),(1,2,3,5,4,6),(1,3,2,4,5,6),(1,3,2,5,4,6),(1,4,2,5,3,6)。
题解
仔细观察奇数项
发现是1,2,3 1,2,4 1,2,5 1,3,4 1,3,5
所以,发现是对于第i项 a[i]<2*i,发现什么
不就是入栈的序列吗
对于1,2,3
出栈,入栈编号都加1,所以
上面五项对应了
进 进 进 出 出 出
进 进 出 进 出 出
进 进 出 出 进 出
进 出 进 进 出 出
进 出 进 出 进 出
这不是就是卡特兰数的应用之一吗,hh
注意分解因数
1 #include<cstdio> 2 #include<cmath> 3 #include<ctime> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 8 #define ll long long 9 #define N 2000007 10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(ch>‘9‘||ch<‘0‘){if (ch==‘-‘) f=-1;ch=getchar();} 15 while(ch<=‘9‘&&ch>=‘0‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} 16 return x*f; 17 } 18 19 ll ans=1; 20 int n,P,cnt; 21 int pri[N],mn[N],num[N]; 22 bool flag[N]; 23 24 void init() 25 { 26 for(int i=2;i<=2*n;i++) 27 { 28 if(!flag[i])pri[++cnt]=i,mn[i]=cnt; 29 for(int j=1;pri[j]*i<=2*n&&j<=cnt;j++) 30 { 31 flag[pri[j]*i]=1;mn[pri[j]*i]=j; 32 if(i%pri[j]==0)break; 33 } 34 } 35 } 36 void solve(int x,int f) 37 { 38 while(x!=1) 39 { 40 num[mn[x]]+=f; 41 x/=pri[mn[x]]; 42 } 43 } 44 int main() 45 { 46 n=read();P=read(); 47 init(); 48 for(int i=2*n;i>n;i--) 49 solve(i,1); 50 for(int i=1;i<=n;i++) 51 solve(i,-1); 52 solve(n+1,-1); 53 for(int i=1;i<=cnt;i++) 54 while(num[i]--) 55 ans=(ans*pri[i])%P; 56 printf("%d\n",ans); 57 }