[来源未知]虚

内存512M,时限1s

【问题描述】
很久以前,Mr.董还只是一个孩子,他每天在家都很空虚,只好随机游走打发时间。
你可以认为董所在的街道是一个数轴,他住在0号,每秒钟他会以1/4的概率向左移动1个单位,以1/4的概率向右移动1个单位,或者以1/2的概率被抽取一秒而不能行动,现在请你告诉他在t秒后到达位置p的概率。
因为答案可能非常小,为了避免精度误差,你需要对1,000,000,007取模后输出。具体来说,显然答案是个有理数a/b,那么请输出一个整数k使得kb模1,000,000,007等于a,实际上由于费马小定理,你需要输出的是a乘以b的1,000,000,005次方。
【输入格式】
第一行两个正整数,分别表示t和p。
【输出格式】
一行一个正整数表示答案。
【样例输入输出】
xu.in xu.out
2 2 562500004
【数据范围与约定】
对于40%的数据t<=15;
对于70%的数据t<=2000;
对于100%的数据|p|,t<=100000。

sol:
设左移为l,右移为r
对题目进行一轮抽象,发现对于停留的操作就是l+r,发现概率不对,那我们把步数和时间都*2,对于原题,l,r为1/4概率,停留为1/2,抽象后,l为l+l,r为r+r,停留为l+r或r+l,那么概率和原题相同,两个等价。
那么对于抽象后,就相当于用2t时间走到2p位置,那么知道这两个东西,我们就能知道l和r的次数,p=abs(p)显然等价原题,那么r-l=2p,r+l=2t,得到l=t-p;r=t+p;组合数算一下方案即可。

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
const int pyz=1e9+7;
const int N=210000;
int n,m,t,p;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
int fac[N],inv[N];
inline int C(int n,int m)
{
    return (ll)fac[n]*inv[m]%pyz*inv[n-m]%pyz;
}
inline int ksm(int s,int t)
{
    int res=1;
    while(t)
    {
        if(t&1) res=(ll)res*s%pyz;
        s=(ll)s*s%pyz;
        t>>=1;
    }
    return res;
}
int main()
{
    freopen("xu.in","r",stdin);
    freopen("xu.out","w",stdout);
    t=read();
    p=abs(read());
    if(t<p) {printf("0");return 0;} 
    t<<=1;
    fac[0]=inv[0]=1;
    for(int i=1;i<=t;++i) fac[i]=(ll)fac[i-1]*i%pyz;
    inv[t]=ksm(fac[t],pyz-2);
    for(int i=t-1;i>=1;--i) inv[i]=(ll)inv[i+1]*(i+1)%pyz;
    printf("%d",(ll)C(t,(t-2*p)/2)*ksm(ksm(2,t),pyz-2)%pyz);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值