【64测试20161112】【Catalan数】【数论】【扩展欧几里得】【逆】

Problem:  

  n个人(偶数)排队,排两行,每一行的身高依次递增,且第二行的人的身高大于对应的第一行的人,问有多少种方案。mod 1e9+9

Solution:

  这道题由1,2,5,14 应该想到Catalan数,但是我却花了两个小时去找递推式。

  首先 Catalan数 :

  基本规律:1,2,5,14,42,132,..........

典型例题:

  1、多边形分割。一个多边形分为若干个三角形有多少种分法。

    C(n)=∑(i=2...n-1)C(i)*C(n-i+1)

  2、排队问题:转化为n个人在第一行为0,第二行为1,则n个人的序列中,在1前面的所有0,1中,0的个数一定要大于1。

        见:http://blog.csdn.net/vast_sea/article/details/8173362      。类似于下一个问题。

  3、出入栈问题:问出入栈的方案数。

    与上一个问题相似,转换为0 为入栈,1为出栈,则合法的出入栈方案有多少?

  4,、括号匹配问题:n对括号有多少种匹配方式?类似于出入栈。

  5、二叉树问题:n个节点的二叉树有多少种形式?

     用T(i,j)表示 左节点 i 个,右节点 j 个。则根节点一定有一个,所以形式数为:T(0,n-1),T(1,n-2),T(2,n-3)....

     f[n]=f[0]*f[n-1]+f[1]*f[n-2]+.....+f[n]*f[0]

其次,Catalan数问题解决后,我们用C(n)=C(n-1)*(4*n-2)/(n-1)求解(不要问我哪里来的,我也不知道)。然后就会发现一个问题:

  A/BmodP 在数据大的情况下可能会出错,而A/BmodP肯定不等于AmodP/BmodP,这时就需要用到 逆元 了。

逆元:

  ax≡1(mod P)    ->  ax mod P=1 mod P = 1  ->    b/a*(ax) mod P == b/a mod P==b*x mod P

即 x 为a mod P的逆元。

求逆元的方式:

  1、扩展欧几里得:

    因为ax≡1(mod P),所以ax-1=nP,即ax-1为P的倍数。所以移项得:ax-nP=1。然后由扩展欧几里得算法推出x的解。

    扩展欧几里得算法推导:

      设 ax1+by1=gcd(a,b)    ∵gcd(a,b)=gcd(b,a%b)   ∴bx2+(a%b)y2=ax1+by1

      ∵a%b=a-(a/b)*b   ∴bx2+ay2-(a/b)*b*y2=ax1+by1

      根据恒等定理:x1=y2;  y1=x2-(a/b)*y2

    这样我们可以用递归求解,直到 b==0,x=1,y=0。递归x2,y2求x1,y1.

 代码:

void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if (b==0){
        d=1;x=1;y=0;
    }
    else {
        gcd(b,a%b,d,y,x);y-=x*(a/b);//注意这里的y,x的区别,在递归的过程中,已经交换了x和y,所以为y-=x*(a/b);
    }
}

  2、费马小定理:

    a^(p-1)≡1(mod P)

    则: a*a^(p-2)≡1(mod P)

    逆元:ax≡1(mod P),则x为a^(p-2),x为a mod P的逆元。可以由快速幂求得,但是如果数据大就太慢。

 代码:

ll ksm(ll x)//快速幂
{
    ll tmp=x,t=1,k=P-2;
    while (k>0){
        if (k%2) t=(t*tmp)%P;
        k=k>>1;
        tmp=(tmp*tmp)%P;
    }
    return t;
}
void pre()
{
    inv[1]=1;
    for (int i=2;i<=N;i++)//费马小定理求 逆
      inv[i]=ksm(i);
}

  这样,就可以A 了这道题。顺带复习了很多数论和递推知识。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define P 1000000009
 6 #define N 1000000
 7 #define ll long long
 8 using namespace std;
 9 int t;
10 ll cat[N];
11 void gcd(ll a,ll b,ll &d,ll &x,ll &y)
12 {
13     if (b==0){
14         d=1;x=1;y=0;
15     }
16     else {
17         gcd(b,a%b,d,y,x);y-=x*(a/b);
18     }
19 }
20 ll inv(ll q,ll w)
21 {
22     ll d,x,y;
23     gcd(q,w,d,x,y);
24     return d==1?(x+w)%w:-1;
25 }
26 void pre()
27 {
28     cat[1]=1;
29     for (int i=2;i<=N;i++)
30       cat[i]=cat[i-1]*(4*i-2)%P*inv(i+1,P)%P;
31 }
32 int main()
33 {
34     freopen("a.in","r",stdin);
35     freopen("a.out","w",stdout);
36     pre();
37     cin>>t;
38     while (t)
39     {
40         int n;
41         scanf("%d",&n);
42         printf("%I64d\n",cat[n/2]);
43         t--;
44     }
45     return 0;
46 }

  

时间: 2024-10-13 07:01:10

【64测试20161112】【Catalan数】【数论】【扩展欧几里得】【逆】的相关文章

POJ 青蛙的约会 1061【经典数论-扩展欧几里得】

Language: Default 青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 98005   Accepted: 18548 Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们

数论 + 扩展欧几里得 - SGU 106. The equation

The equation Problem's Link Mean: 给你7个数,a,b,c,x1,x2,y1,y2.求满足a*x+b*y=-c的解x满足x1<=x<=x2,y满足y1<=y<=y2.求满足条件的解的个数. analyse: 做法是扩展欧几里德. 1.首先是欧几里德算法,欧几里德算法是用于求任意两个数的最大公约数(gcd(a,b)), 这个方法基于一个定理,gcd(a,b)=gcd(b,a % b)(a>b),%表示取模. 我们来证明上述定理,因为a>b,

NYOJ-整数性质(扩展欧几里得)

整数性质 时间限制:500 ms  |  内存限制:65535 KB 难度:1 描述 我们知道,在数学中,对于任意两个正整数a和b,必定存在一对整数s.t使得sa+tb=gcd(a,b). 输入 多组测试数据. 每组数据输入两个非负整数a和b且a+b>0且a不等于b. 其中0<=a,b<100000. 输出 输出满足条件的 s 和 t . 样例输入 2 4 3 8 737 635 样例输出 1 0 3 -1 193 -224 代码: #include<stdio.h> voi

【数论】【扩展欧几里得】Codeforces 710D Two Arithmetic Progressions

题目链接: http://codeforces.com/problemset/problem/710/D 题目大意: 两个等差数列a1x+b1和a2x+b2,求L到R区间内重叠的点有几个. 0 < a1, a2 ≤ 2·109,  - 2·109 ≤ b1, b2, L, R ≤ 2·109, L ≤ R). 题目思路: [数论][扩展欧几里得] 据题意可得同余方程组 x=b1(mod a1) 即 x=k1*a1+b1 x=b2(mod a2) x=k2*a2+b2 化简,k1*a1=k2*a2

数论(欧几里得,扩展欧几里得,欧拉)

今天考试了,三道题分别是求欧拉,逆欧拉,欧拉求和 对于我这样的蒟蒻来说,我选择狗带. 爆零稳稳的. 现在整理一下: φ(n)(欧拉函数值)为不大于n的正整数中与n互质的数的个数: 有几条这样的性质: 1.欧拉函数是积性函数,但不是完全积性函数,即φ(mn)=φ(n)*φ(m)只在(n,m)=1时成立. 2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn. φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn). 3.除了N=2,φ(N)都是偶数.

数论杂谈——欧几里得算法及扩展欧几里得

数学是oi的重要基础,所以说数论在oi中占据了非常重要的地位,因此,学好数学,对于一个oier来说也是非常重要的. oi中的数学,其实也就和数竞并没有什么区别. 欧几里得法辗转相除法求最大公约数 我们可以证明gcd(a,b)=gcd(b,a%b),也就是我国古代数学智慧的结晶,更相损减术.并且一直递归下去,直到b的值为零,最大公约数值即为a.在这里就不给出详细证明了,大家可以代几个数据去验证它一下.谁叫我数学太菜. 代码如下 int GCD(int a,int b) { if(!b) { ret

JZYZOJ1371 青蛙的约会 扩展欧几里得 GTMD数论

http://172.20.6.3/Problem_Show.asp?id=1371 http://www.cnblogs.com/jackge/archive/2013/04/22/3034925.html详细的题解,大概是网上能看到的最简单易懂的扩展欧几里得讲解了 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include&

UVa 11768 格点判定(扩展欧几里得求线段整点)

https://vjudge.net/problem/UVA-11768 题意: 给定两个点A(x1,y1)和B(x2,y2),均为0.1的整数倍.统计选段AB穿过多少个整点. 思路: 做了这道题之后对于扩展欧几里得有了全面的了解. 根据两点式公式求出直线 ,那么ax+by=c 中的a.b.c都可以确定下来了. 接下来首先去计算出一组解(x0,y0),因为根据这一组解,你可以写出它的任意解,其中,K取任何整数. 需要注意的是,这个 a' 和 b' 是很重要的,比如说 b' ,它代表的是x每隔 b

gcd,扩展欧几里得,中国剩余定理

1.gcd: int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } 2.中国剩余定理: 题目:学生A依次给n个整数a[],学生B相应给n个正整数m[]且两两互素,老师提出问题:有一正整数ans,对于每一对数,都有:(ans-a[i])mod m[i]=0.求此数最小为多少. 输入样例: 1 10 2 3 1 2 3 2 3 5 8 1 2 3 4 5 6 7 8 97 89 67 61 59 53 47 88 12 1 2 3 4 5 6 7 8 9