BestCoder Round #81 (div.1) C HDU 5673 卡特兰数




链接:戳这里


Robot
 Time Limit: 12000/6000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
有一个机器人位于坐标原点上。每秒钟机器人都可以向右移到一个单位距离,或者在原地不动。如果机器人的当前位置在原点右侧,它同样可以
向左移动单位距离。一系列的移动(左移,右移,原地不动)定义为一个路径。问有多少种不同的路径,使得n秒后机器人仍然位于坐标原点?
答案可能很大,只需输出答案对1,000,000,007的模。
输入描述
输入包含多组数据. 第一行有一个整数T(1≤T≤100), 表示测试数据的组数. 对于每组数据:
输入一个整数 n(1≤n≤1,000,000)。
输出描述
对于每组数据,输出一个整数
输入样例
3
1
2
4
输出样例
1
2
9


思路:

机器人可以选择向右向左或者不走,我们抽象出来一下

机器人不能走到原点的左边,定义机器人当前向右走的步数numR,机器人向左走的步数为numL

那么不动的步数为n-numR-numL

分析一下只有当numR==numL的时候机器人才能回到原点,这个也就是卡他兰数的的经典例子了...略

所以我们所要的方案就是在n步中选出2*i步来让机器人满足 numR=i && numL=i 使得回到原点

枚举这个i并累加贡献

Ans(n)=i=02nCn2i * Catalan(i)

卡特兰数定义:Catalan(n)=\frac{C_{2n}^n}{n+1}Catalan(n)= C(2*n,n)/(n+1)

由于这道题需要取模,我这里用到了费马小定理推出

a^b%mod = a^( (b%(mod-1) )%mod

(1/x) % mod = x^(mod-2)%mod

预处理出1e6中的卡特兰数和C(n,2*i)

详细的过程看代码吧


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
#define mod 1000000007
using namespace std;
ll F[1000100];
ll anw[1000100],cata[1000100],Q[1000100];
ll Qpow(ll a,ll b,ll P){
    ll ans=1;
    while(b){
        if(b%2) ans=ans*a%P;
        a=a*a%P;
        b/=2;
    }
    return ans%P;
}
ll C(ll n,ll m,ll P){
    return F[n]*Q[m]%P*Q[n-m]%P;
    /*
        (m!)^(-1)%P = (m!)^(P-2)%P
        对于每次的C(n,m,P)来说都需要Qpow一次,强行加了logN   我也是这里一直T
        所以预处理出所有的(m!)^(P-2)%P的值省去logN
    */
}
int main(){
    Q[0]=F[0]=cata[0]=1;
    for(int i=1;i<=1000000;i++) {
        F[i]=F[i-1]*i%mod;
        Q[i]=Qpow(F[i],mod-2,mod);
        ///cata[i]=cata[i-1]*(4*i-2)%mod*Qpow(i+1,mod-2,mod)%mod;
    }
    /// 预处理出所有的卡特兰数
    for(int i=1;i<=1000000;i++) cata[i]=C(2*i,i,mod)*Qpow(i+1,mod-2,mod)%mod;
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        ll ans=0;
        for(int i=0;i<=n/2;i++){
            ans+=C(n,2*i,mod)*cata[i]%mod;
            ans%=mod;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}<strong>
</strong>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值