HDU 4828

其实。。这题是《组合数学》的习题中的一道。。。。。。当初不会。。。。。

想到一个证明:

填入2n个数,把填在上方的数的位置填上+1,下方的填上-1。这样,在序列1....2n的位置,任意前部分和都是>=0且是符合题意的。为什么?首先,可以知道,按+1/-1的位置按顺序在上方或下方填数,必定是符合递增的。其次,是否存在不符合部分和>=0而又满足题意的呢?不妨设最小不符合部分和的数为k,则k必在下方。那么,必定要在它的上方填上一个比它小的赋为+1值的位置的数吧。而前k-1个数必为偶数,又因为要满足递增要求,必定是刚好填满两行的前(k-1)/2个格子,这样,就找不到可以填在k上方的数了。所以,任意前部分和都是>=0且是符合题意的。

所以,这个数必定是卡特兰数。

事后诸葛亮了一把。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL __int64
#define M 1000000007
#define N 1000000
using namespace std;

LL Cata[N+1];

void exgcd(__int64 a,__int64 b,__int64 &x,__int64 &y){
    if(b==0){
        x=1; y=0;
        return ;
    }
    exgcd(b,a%b,x,y);
    __int64 t=x;
    x=y;
    y=t-a/b*y;
}

void initial(){
	Cata[1]=1;
	LL x,y;
	for(int i=2;i<=N;i++){
		Cata[i]=(Cata[i-1]*(4*i-2))%M;
		exgcd(i+1,M,x,y);
		Cata[i]=((Cata[i]*((x%M+M)%M))%M+M)%M;
	}
}

int main(){
	LL n;int T,kase=0;
	initial();
	scanf("%d",&T);
	while(T--){
		scanf("%I64d",&n);
		printf("Case #%d:\n",++kase);
		printf("%I64d\n",Cata[n]);
	}
	return 0;
}

  

时间: 2024-08-05 20:52:23

HDU 4828的相关文章

hdu 4828 Grids(拓展欧几里得+卡特兰数)

题目链接:hdu 4828 Grids 题目大意:略. 解题思路:将上一行看成是入栈,下一行看成是出栈,那么执着的方案就是卡特兰数,用递推的方式求解. #include <cstdio> #include <cstring> typedef long long ll; const int N = 1000005; const ll MOD = 1e9+7; ll dp[N]; ll extendGcd(ll a, ll b, ll& x, ll& y) { if (

HDU 4828 (卡特兰数+逆元)

HDU 4828 Grids 思路:可以转化为卡特兰数,先把前n个人标为0,后n个人标为1,然后去全排列,全排列的数列,如果每个1的前面对应的0大于等于1,那么就是满足的序列,如果把0看成入栈,1看成出栈,那么就等价于n个元素入栈出栈,求符合条件的出栈序列,这个就是卡特兰数了.然后去递推一下解,过程中需要求逆元去计算 代码: #include <stdio.h> #include <string.h> const int N = 1000005; const long long M

HDU 4828 Grids

这道题我做了很久,推出来一个过程,但是那样做是n^2的复杂度,这道题做不了.后来,上网上搜了一下题解,才发现这个原来叫做卡特兰数...真心给跪了,到底我是有多无知啊!!  还有一个递推公式,不,应该说有很多,我选择了一个,不,是除题解的那人选了一个最好用的. 不光是这样,我还终于明白了逆元的终极奥义.原来他是用来抵消运算的,或者说是换了一种形式,变加为减,变除为乘.说到乘法逆元,尤其是求模的逆元,当然少不了ex_gcd()了. 下面的是代码 #include <iostream> #inclu

HDU 4828 (卡特兰数+逆)

HDU 4828 Grids 思路:能够转化为卡特兰数,先把前n个人标为0.后n个人标为1.然后去全排列,全排列的数列.假设每一个1的前面相应的0大于等于1,那么就是满足的序列,假设把0看成入栈,1看成出栈.那么就等价于n个元素入栈出栈,求符合条件的出栈序列,这个就是卡特兰数了. 然后去递推一下解,过程中须要求逆元去计算 代码: #include <stdio.h> #include <string.h> const int N = 1000005; const long long

hdu 4828 Xor Sum (trie 树模板题,经典应用)

hdu 4825 题目链接 题意:给定n个数,然后给出m个询问,每组询问一个数x,问n中的数y使得x和y的异或和最大. 思路:字典树..把每个数转化成二进制,注意补全前导0,使得所有数都有相同的位数. 如果想要异或和最大,那么每一位尽可能都是1. 所以做法是,先构建字典树,然后每次find的时候,尽可能按照和当前寻找的数的位相反的位的方向走(如果有的话) 比如当前位是1,那我就往0的方向走. 需要注意的是,多组数据,每次要重新初始化一遍. 做法是 在struct 中重新 root = new N

HDU 4828 - Grids (Catalan数)

题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=4828 Catalan数的公式为 C[n+1] = C[n] * (4 * n + 2) / (n + 2) 题目要求对M = 1e9+7 取模 利用乘法逆元将原式中除以(n+2)取模变为对(n+2)逆元的乘法取模 C[n+1] = C[n] * (4 * n + 2) * Pow(n+2, MOD-2) % MOD 其中Pow用快速幂解决 #include <cstdio> #include

HDU 4828 逆元+catalan数

Grids Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 953    Accepted Submission(s): 418 Problem Description 度度熊最近很喜欢玩游戏.这一天他在纸上画了一个2行N列的长方形格子.他想把1到2N这些数依次放进去,但是为了使格子看起来优美,他想找到使每行每列都递增的方案.不过画了很

HDU 4828 Grids(卡特兰数+乘法逆元)

首先我按着我的理解说一下它为什么是卡特兰数,首先卡特兰数有一个很典型的应用就是求1~N个自然数出栈情况的种类数.而这里正好就对应了这种情况.我们要满足题目中给的条件,数字应该是从小到大放置的,1肯定在左上角,所以1入栈,这时候我们放2,如果我们把2放在了1的下面就代表了1出栈,把2放在上面就代表了2也进栈(可以看一下hint中第二组样例提示),以此类推,这样去放数,正好就对应了上面一行入栈,下面一行出栈的情况,一共n行,对应上限为n的卡特兰数. 需要注意的地方就是在使用卡特兰数递推式的时候,除法

数论(一)

HDU 2669 ex_GCD HDU 1576 逆元,ex_GCD HDU 4828 卡特兰数 假设,依次放1-n,放第一排记为0,放第二排记为1,题目的条件就转化为卡特兰数的条件了 附:线性求逆元,卡特兰数(递推) p[1] = 1; for (int i = 2; i < 1000003; i++) { p[i] = - (MODP / i) * p[MODP % i]; p[i] = (p[i] % MODP + MODP) % MODP; } f[1] = 1; for (int i