51nod 1119 机器人走方格V2(求组合数,费马小定理+快速幂/逆元+gcd)

来源:互联网 发布:卖家做淘宝客怎么玩 编辑:程序博客网 时间:2024/05/16 03:41

题目:点击打开链接

额,,,走方格不是走边。

杨辉三角形,从A出发到每个点的走法数等于它左边点和上边点的走法相加
1  1  1    1

1  2  3    4

1  3  6   10

1  4    10    20




可以看出结果为C(min(n-1,m-1),n+m-2 )     

令m+n-2=m, m-1=n, 即c(n, m)=m!/((n-m)!*n!)%N;  再令:a=m!/(m-n)!,b=n!;

所以只需要求 a / b%N;但a,b本身就超过long long了,为了防止溢出,可以(a%N )/ (b%N)%N,但我们发现除法没法这么算,

因为比如9 / 3%14,搞完3%14成0了,b%N经常会变成0,会出错。

所以可以这么处理:利用费马小定理

费马小定理:b^(N - 1)=1(mod N),前提是b是整数,N是质数,b,N互质,显然符合

而a / b=x(mod N),两边关于N互余

两边相乘,得,a * b^(N - 2)=x(mod N);用快速幂处理即可。

#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#define ll long longusing namespace std;const ll mod=1e9+7;ll get_pow(ll x, ll n){  //快速幂    ll ans=1;    while(n){        if(n&1){            ans=ans*x%mod;        }        x=x*x%mod;        n>>=1;    }    return (ans+mod)%mod;}ll C(ll n,ll m){  //C(n,m),m里选n个。    ll ans,a=1,b=1;    for(ll i=m;i>=m-n+1;i--)        a=a*i%mod;    for(ll i=n;i>1;i--)        b=b*i%mod;    ans=a*get_pow(b,mod-2)%mod;    return ans;}int main(){    ll n,m;    cin>>n>>m;    ll ans=C(min(n-1,m-1),m+n-2);      cout<<ans<<endl;    return 0;}

还有一种处理方法比较类似,求逆元。

可以转化为求a * b'%N,其中b’为%N的乘法逆元。

#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#define ll long longusing namespace std;const ll mod=1e9+7;void gcd(ll a,ll b,ll &d,ll &x,ll &y){    if(!b){d=a;x=1;y=0;}    else{ gcd(b,a%b,d,y,x);y-=x*(a/b);}}ll inv(ll a,ll n){    ll d,x,y;    gcd(a,n,d,x,y);    return d==1? (x+n)%n:-1;}ll C(ll n,ll m){  //C(n,m),m里选n个。    ll ans,a=1,b=1;    for(ll i=m;i>=m-n+1;i--)        a=a*i%mod;    for(ll i=n;i>1;i--)        b=b*i%mod;    ans=a*inv(b,mod)%mod;    return ans;}int main(){    ll n,m;    cin>>n>>m;    ll ans=C(min(n-1,m-1),m+n-2);    cout<<ans<<endl;    return 0;}


阅读全文
0 0