思路:
正难则反
//C(M+N,M)*C(Q+M-P,Q)-C(N+M-P,N)*C(M+Q,M);
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"stack"
#include"algorithm"
#include"iostream"
using namespace std;
#define ll long long
#define mod 100000007
//C(M+N,M)*C(Q+M-P,Q)-C(N+M-P,N)*C(M+Q,M);
ll inverse[100005];
ll power(ll a,ll b) //关于逆元 其实如果mod是素数 则b的逆元其实就是b^(mod-2)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll t,r=exgcd(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
return r;
}
ll get_inverse(ll a) //exgcd求逆元
{
ll x,y;
exgcd(a,mod,x,y);
return (x%mod+mod)%mod;
}
ll fc(ll n,ll m)
{
/*ll t1,t2; //数据小的话直接乘起来最后求一次逆元快
t1=t2=1;
for(ll i=n;i>m;i--)
{
t1=(t1*i)%mod;
t2=(t2*(i-m))%mod;
}
return t1*get_inverse(t2)%mod;*/
ll ans=1; //如果数据比较大 先预处理会用到的逆元 然后每次都乘逆元
for(ll i=n; i>m; i--)
{
ans=(ans*i)%mod;
ans=(ans*inverse[i-m])%mod;
}
return ans;
}
int main()
{
ll m,n,p,q;
for(int i=1; i<=100000; i++) inverse[i]=power(i,mod-2); //预处理逆元
for(int i=1; i<=100000; i++) inverse[i]=get_inverse(i); //预处理逆元
while(scanf("%lld%lld%lld%lld",&m,&n,&p,&q)!=-1)
{
ll a,b,c,d,ans;
a=fc(m+n,m);
b=fc(q+m-p,q);
c=fc(n+m-p,n);
d=fc(m+q,m);
ans=(a*b)%mod-(c*d)%mod;
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}
[组合数取模-逆元计算模板] zoj 3624 Count Path Pair
原文:http://blog.csdn.net/wdcjdtc/article/details/40921227