内存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);
}