sdut 3895/第八届省赛C题 fireworks 杨辉三角 逆元求C(n,m)%mod

来源:互联网 发布:网络歌手樊棋照片 编辑:程序博客网 时间:2024/06/05 09:22

题目链接

题意:

给你n个烟花,时间 t和要查询的位置w,每一个烟花都是朝其两边传并消失掉,问你第t时刻w位置有几个烟花/

思路:

     省赛那天一直以为这个是个规律....

我们首先假设一个位置有烟花,我们往下穿几次就会发现规律了

1

1

20 1

30 3 1

1 06 0 1


可以发现如果把0去掉了对于每一个有烟花的位置就会变成一个杨辉三角了。

我们只关心第 t 秒 w 处位置有几个烟花,那么对于离烟花距离左右大于t的就不管了也不会对要查询的位置产生什么影响.

那么我们就确定了 范围区间(x-t,x+t) 还可以发现离左端点距离为奇数的这一时刻肯定为0,所以我们还要计算w和左端点的差.

  这么大的n和t杨辉三角递推肯定不行了,我们联想到组合数,利用杨辉三角和组合数的关系,用逆元来求组合数

这里我用的是费马小定理逆元求组合数,先预处理阶乘和逆元就可以了.

求C(n,m)%mod的方法总结

#include<bits/stdc++.h>#define Ri(a) scanf("%d", &a)#define Rl(a) scanf("%lld", &a)#define Rf(a) scanf("%lf", &a)#define Rs(a) scanf("%s", a)#define Pi(a) printf("%d\n", (a))#define Pf(a) printf("%lf\n", (a))#define Pl(a) printf("%lld\n", (a))#define Ps(a) printf("%s\n", (a))#define W(a) while(a--)#define CLR(a, b) memset(a, (b), sizeof(a))#define MOD 1000000007#define inf 0x3f3f3f3fusing namespace std;typedef long long ll;const int maxn=1e5+10;int n,t,w;ll num[maxn];void init(){    num[0]=1;    num[1]=1;    for(int i=2;i<=1e5;i++)    {        num[i]=(num[i-1]*i)%MOD;    }    return ;}ll quickpow(ll a,ll b){    ll ans=1;    a%=MOD;    b%=MOD;    while(b)    {        if(b&1)        ans=(ans*a)%MOD;        b/=2;        a=(a*a)%MOD;    }    return ans;}ll cal(ll a,ll b){    ll ans=1;    if(a<b)    return 0;    ans=(ans*num[a]*quickpow((num[b]*num[a-b])%MOD,MOD-2))%MOD;    return ans;}int main(){    init();    int x,c;    while(~Ri(n))    {        Ri(t),Ri(w);        ll temp=0;        for(int i=1;i<=n;i++)        {            Ri(x),Ri(c);            ll l=x-t;            ll r=x+t;            ll pos=(w-l);            if(w<l||w>r||pos%2!=0)            continue;            temp=(temp+c*cal(t,pos/2))%MOD;        }        Pl(temp);    }    return 0; }/***************************************************User name: ¸ÖÌúÏÀResult: AcceptedTake time: 412msTake Memory: 1004KBSubmit time: 2017-05-09 19:52:29****************************************************/


1 0