有一个长度为2n的1~2n的全排列,保证其奇数项递增,偶数项递增,并且相邻的奇数项和偶数项,后面的偶数项大于奇数项的方案数(mod p,n<=1000000,P<=1000000000)。
解
注意到2n,实际上也就猜到它可能为catalan数列了,再看看样例,(1,2,5,14),显然为catalan数,故可以猜测为catalan数,在套个质因数分解阶乘求组合数上去就可以了。
现在在于如何证明,注意到元素不为2个,于是考虑已学模型有多个元素的自然也只有栈,于是考虑去构造栈的模型,因为有递增的要求,所以入栈序必然要让其为递增的,即有1~2n等着去入栈,显然每次入栈的数要比前面都要大,然而又要想办法把它压到n个元素,栈只有n个元素,于是自然会给出两个容器,一个装奇数,一个装偶数,自然奇数容器里面会是递增的,而偶数容器也一样,但是问题在于偶数容器里面是否能保证每个偶数都要对应比奇数大,显然按照我们这种入栈的方式,只要保证任意一次操作偶数入栈的数量比奇数入栈次数少即可,于是也就成功地转化成了catalan模型。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
using namespace std;
bool check[2000001];
int yyb,prime[200000],pt;
il void sieve(int);
il int cat(int),pow(int,int);
int main(){
int n;
scanf("%d%d",&n,&yyb),sieve(n<<1);
printf("%d",cat(n));
return 0;
}
il void sieve(int n){
int i,j;
for(i=2;i<=n;++i){
if(!check[i])prime[++pt]=i;
for(j=1;j<=pt&&prime[j]<=n/i;++j){
check[i*prime[j]]|=true;
if(!(i%prime[j]))break;
}
}
}
il int pow(int x,int y){
int ans(1);while(y){
if(y&1)ans=(ll)ans*x%yyb;
x=(ll)x*x%yyb,y>>=1;
}return ans;
}
il int cat(int n){
int n2(n<<1),i,j,tr(0),xdk(n+1),
ans(1);
for(i=1;i<=pt;++i,tr&=0){
for(j=n2;j;j/=prime[i])tr+=j/prime[i];
for(j=n;j;j/=prime[i])tr-=j/prime[i]<<1;
while(!(xdk%prime[i]))xdk/=prime[i],--tr;
ans=(ll)ans*pow(prime[i],tr)%yyb;
}return ans;
}