1. 程式人生 > >hdu5698 組合數學(求組合數)

hdu5698 組合數學(求組合數)

這題真的是有點煩人。
首先可以想到相當於是在左上角區域內選0到min(m-2,n-2)個點,然後求和。
(假設m<=n)也就是

i=0m2m2in2i
雖然這樣已經可以AC了,但是這個式子是可以化簡的。
要用到這樣一個性質:i=0rm+ii=m+r+1r
證明如下:
首先知道,C(m-1,n)+C(m-1,n-1)=C(m,n),
然後:
i=0rm+ii
=m0+m+
11+m+22+...+m+rr

=m+10+m+11+m+22+...+m+rr
=m+21+m+22+...+m+rr
=m+r+1r
套用這個性質,我們就可以得到答案就是C(m+n-4,m-2);
不過得到這個之後我就寫了個分解素因數算了個組合數,然後就很糟心地TLE了.
正兒八經地寫個逆元就不會T:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; const int maxn=1e5+5; const int mo=1e9+7; long long jie[2*maxn]; int n,m; long long Pow(long long a,int b) { long long ans=1; while(b) { if(b&1) ans=ans*a%mo; a=a*a%mo; b>>=1; } return ans; } void init() { jie[0]=1; for
(int i=1;i<2*maxn;i++) jie[i]=jie[i-1]*i%mo; } long long cal(long long a,long long b) { int temp=(jie[b]*jie[a-b])%mo; return (jie[a]*Pow(temp,mo-2))%mo; } int main() { init(); scanf("%d%d",&n,&m); long long ans=cal(n+m-4,n-2); printf("%lld\n",ans); return 0; }