(上不了p站我要死了,侵权度娘背锅)

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)。

首先这是一个卡特兰数

我们思考把1~n的数字按顺序摆放。因为分了奇数和偶数,就相当于分了两组队列,我们把这n个数按顺序放入两组队列里。由于任何时候奇数队列里的元素个数都大于等于偶数队列里的,所以是卡特兰的一个经典模型。

答案即为C(2n,n)/(n+1) mod p

但是发现p并不是一个质数,所以不能求逆元,就不能直接用阶乘的公式来做。

这里就有一个很重要的方法了

虽然是模任意数,但是n的范围是o(n)可过的。我们筛出需要的数(如n)的阶乘(n!)中每个素数的指数。具体做法为:

设cnt[i]表示该阶乘(n!)中包含多少个i,进行线性递推。初始值cnt[i]=1。

依次枚举n到1,跳过质数。设minp[i]为i的最小质因子,cnt[i/minp[i]]+=cnt[i], cnt[minp[i]]+=cnt[i], cnt[i]=0。

这部分的代码(init()为线性筛):

init();
for(int i=n*2;i>=2;i--){
cnt[i]++;
if(!notp[i]) continue;
cnt[i/minp[i]]+=cnt[i];
cnt[minp[i]]+=cnt[i];
cnt[i]=0;
}

这样就将除法问题转化为了质数的相减问题,得出C(2n,n)/(n+1)中每个质数的指数,再做快速幂。

时间复杂度:根据某素数定理,n中的素数个数约为 n/ln n 个,快速幂是 log n 的。所以乘起来约为o(n)

完整代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#ifdef WIN32
#define RIN "%I64d"
#else
#define RIN "%lld"
#endif const int N=1000000+5; int cnt1[N*2],cnt2[N*2],cnt3[N*2];
int notp[N*2],cntp=0,prime[N*2],minp[N*2];
int n,p; void init(){
notp[1]=1;
for(int i=2;i<=n*2;i++){
if(!notp[i])
prime[++cntp]=i;
for(int j=1;j<=cntp&&i*prime[j]<=n*2;j++){
notp[i*prime[j]]=1;
minp[i*prime[j]]=prime[j];
if(i%prime[j]==0) break;
}
}
}
ll power(int a,int b){
ll rt=1;
for(;b;b>>=1,a=(a*a)%p)
if(b&1) rt=(rt*a)%p;
return rt;
}
int main(){
scanf("%d%d",&n,&p);
init();
for(int i=n*2;i>=2;i--){
cnt1[i]++;
if(!notp[i]) continue;
cnt1[i/minp[i]]+=cnt1[i];
cnt1[minp[i]]+=cnt1[i];
cnt1[i]=0;
}
for(int i=n;i>=2;i--){
cnt2[i]++;
if(!notp[i]) continue;
cnt2[i/minp[i]]+=cnt2[i];
cnt2[minp[i]]+=cnt2[i];
cnt2[i]=0;
}
for(int i=n+1;i>=2;i--){
cnt3[i]++;
if(!notp[i]) continue;
cnt3[i/minp[i]]+=cnt3[i];
cnt3[minp[i]]+=cnt3[i];
cnt3[i]=0;
}
ll ans=1;
for(int i=1;i<=cntp;i++){
int tmp=prime[i];//printf("%d %d %d\n",cnt1[tmp],cnt2[tmp],cnt3[tmp]);
ans=(ans*power(prime[i],cnt1[tmp]-cnt2[tmp]-cnt3[tmp]))%p;
}
printf(RIN"\n",ans);
return 0;
}

【bzoj1485:】【 [HNOI2009]有趣的数列】模任意数的卡特兰数的更多相关文章

  1. bzoj1485: [HNOI2009]有趣的数列(Catalan数)

    1485: [HNOI2009]有趣的数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2105  Solved: 1117[Submit][Stat ...

  2. [bzoj1485][HNOI2009]有趣的数列_卡特兰数_组合数

    有趣的数列 bzoj-1485 HNOI-2009 题目大意:求所有1~2n的排列满足奇数项递增,偶数项递增.相邻奇数项大于偶数项的序列个数%P. 注释:$1\le n\le 10^6$,$1\le ...

  3. 【卡特兰数】BZOJ1485: [HNOI2009]有趣的数列

    Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…&l ...

  4. BZOJ1485:[HNOI2009]有趣的数列(卡特兰数)

    Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…&l ...

  5. BZOJ1485: [HNOI2009]有趣的数列(Catalan数,质因数分解求组合数)

    题意 挺简洁的. 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…<a ...

  6. BZOJ1485: [HNOI2009]有趣的数列(卡特兰数+快速幂)

    题目链接 传送门 题面 思路 打表可以发现前六项分别为1,2,5,12,42,132,加上\(n=0\)时的1构成了卡特兰数的前几项. 看别人的题解说把每一个数扫一遍,奇数项当成入栈,偶数项当成出栈, ...

  7. bzoj1485: [HNOI2009]有趣的数列(Catalan数)

    一眼卡特兰数...写完才发现不对劲,样例怎么输出$0$...原来模数不一定是质数= =... 第一次见到模数不是质数的求组合数方法$(n,m\leq 10^7)$,记录一下... 先对于$1$~$n$ ...

  8. BZOJ1485: [HNOI2009]有趣的数列

    Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…&l ...

  9. [HNOI2009]有趣的数列 题解(卡特兰数)

    [HNOI2009]有趣的数列 Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满 ...

  10. 洛谷P3200 [HNOI2009]有趣的数列(Catalan数)

    P3200 [HNOI2009]有趣的数列 题目描述 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足 ...

随机推荐

  1. Python学习1,代码

      看了好久的网上视频,今天尝试着写了一串代码: _author_ = "Happyboy" produce_list = [ ('Iphone',5800), ('Mac Pro ...

  2. 构建Docker镜像两种方式的比较-Dockerfile方式和S2I方式

    前言 写Dockerfile是构建Docker镜像最通常的方式,接触过Docker的童鞋多少了解一些.前段时间研究OpenShift(paas的一种),发现了另外一种构建Docker镜像的方式:S2I ...

  3. java中从实体类中取值会忽略的的问题

    在我们java Map中通过get来取值时会忽略的问题是:如果取得一个空值null时,那么.toString()时就会出错,而且不知道是什么原因. 现在我给的具体方法是用条件表达式先判断一下. 例: ...

  4. 【BestCoder #48】

    与之前一样,秒刷A和B,然后就永远卡在了C B也因为少看一句话被Hunt掉了 说说C的做法吧(分块大法好 给定一个序列,每次询问区间l-r,求∑(ai^bi),其中bi是指ai在区间中的出现次数,ai ...

  5. [poj] 1149 PIGS || 最大流经典题目

    原题 题目大意 给你m个猪圈以及每个猪圈里原来有多少头猪,先后给你n个人,每个人能打开一些猪圈并且他们最多想买Ki头猪,在每一个人买完后能将打开的猪圈中的猪顺意分配在这次打开猪圈里,在下一个人来之前 ...

  6. BZOJ1951 [Sdoi2010]古代猪文 【费马小定理 + Lucas定理 + 中国剩余定理 + 逆元递推 + 扩展欧几里得】

    题目 "在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心--" --选自猪王国民歌 很久很久以前,在山的那 ...

  7. java中的URLEncoder.encode对应JS中用decodeURIComponent,js和java编码,解码

    用get请求传中文,经常搞到乱码,这几天搞搞这个东西,总结一下,以方便以后处理这类的问题. Java代码中的URLEncoder.encode方法和JS的encodeURIComponent功能差不多 ...

  8. python request模板

    # -*- coding: utf-8 -*- import time import requests class Request: def __init__(self): self.s=reques ...

  9. sublime text常用快捷键及多行列模式批量操作教程

    列模式 苹果:OS X -鼠标左键+Option -或者鼠标中键 -增加选择:Command,减少选择:Command+Shift 2 Windows: -鼠标右键+Shift -或者鼠标中键 -增加 ...

  10. 文件排版(codevs 1300)

    题目描述 Description 写电子邮件是有趣的,但不幸的是经常写不好看,主要是因为所有的行不一样长,你的上司想要发排版精美的电子邮件,你的任务是为他编写一个电子邮件排版程序. 完成这个任务最简单 ...