Codeforces 559C Gerald and Giant Chess(DP+乘法逆元求大組合數)
阿新 • • 發佈:2019-02-04
先把黑塊按座標排序。
dp[i]表示到第i個黑塊且之前沒有經過黑塊的方案數,那麼每一個dp[i]中的方案都是完全不相同的。遞推的方法是dp[i]=C(xi+yi,xi)-sum(dp[j]*C(xi-xj+yi-yj,xi-xj)) (j<i)
dp[j]*C(xi-xj+yi-yj,xi-xj)就是從1,1經過第j個黑塊到i的路徑數,用總路徑數減去所有的這些不合法的路徑數就是dp[i],(剪去的路徑中沒有重複的)。
由於組合數太大,需要用乘法逆元預處理出每個階乘的逆元。模板在下面。
pair的預設排序規則就是先按key再按value從小到大。
注意預處理階乘要到2*100000
程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#include <map>
#include <algorithm>
#define LL long long
const int mod=1e9+7;
#include <vector>
LL fact[200200];
LL ifact[200200];
int h,w,n;
LL dp[2005];
pair<int,int> G[2005];
LL ex(LL a,LL e)
{
if(e==0) return 1;
LL res=ex(a,e/2);
res*=res;
res%=mod;
if(e%2==1) res*=a;
res%=mod;
return res;
}
LL inv(LL a)
{
return ex(a,mod-2);
}
LL C(int h,int w)
{
if(h<0||w<0) return 0;
LL res=fact[h+w];
res*=ifact[h];
res%=mod;
res*=ifact[w];
res%=mod;
return res;
}
void init(){
fact[0]=1;
ifact[0]=1;
for(int i=1; i<200005; i++)
{
fact[i]=fact[i-1]*i;
fact[i]%=mod;
ifact[i]=inv(fact[i]);
}
}
int main(){
scanf("%d%d%d",&h,&w,&n);
init();
for(int i=0;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
G[i]=make_pair(x,y);
}
sort(G,G+n);
G[n]=make_pair(h,w);
for(int i=0;i<=n;i++){
int x=G[i].first-1,y=G[i].second-1;
dp[i]=C(x,y);
for(int j=0;j<i;j++){
int xx=G[i].first-G[j].first;
int yy=G[i].second-G[j].second;
LL tmp=C(xx,yy)*dp[j];
tmp%=mod;
dp[i]-=tmp;
while(dp[i]<0) dp[i]+=mod;
}
}
printf("%lld\n",dp[n]);
}
dp[i]表示到第i個黑塊且之前沒有經過黑塊的方案數,那麼每一個dp[i]中的方案都是完全不相同的。遞推的方法是dp[i]=C(xi+yi,xi)-sum(dp[j]*C(xi-xj+yi-yj,xi-xj)) (j<i)
dp[j]*C(xi-xj+yi-yj,xi-xj)就是從1,1經過第j個黑塊到i的路徑數,用總路徑數減去所有的這些不合法的路徑數就是dp[i],(剪去的路徑中沒有重複的)。
由於組合數太大,需要用乘法逆元預處理出每個階乘的逆元。模板在下面。
pair的預設排序規則就是先按key再按value從小到大。
注意預處理階乘要到2*100000
程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#include <map>
#include <algorithm>
#define LL long long
const int mod=1e9+7;
#include <vector>
LL fact[200200];
LL ifact[200200];
int h,w,n;
LL dp[2005];
pair<int,int> G[2005];
LL ex(LL a,LL e)
{
if(e==0) return 1;
LL res=ex(a,e/2);
res*=res;
res%=mod;
if(e%2==1) res*=a;
res%=mod;
return res;
}
LL inv(LL a)
{
return ex(a,mod-2);
}
LL C(int h,int w)
{
if(h<0||w<0) return 0;
LL res=fact[h+w];
res*=ifact[h];
res%=mod;
res*=ifact[w];
res%=mod;
return res;
}
void init(){
fact[0]=1;
ifact[0]=1;
for(int i=1; i<200005; i++)
{
fact[i]=fact[i-1]*i;
fact[i]%=mod;
ifact[i]=inv(fact[i]);
}
}
int main(){
scanf("%d%d%d",&h,&w,&n);
init();
for(int i=0;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
G[i]=make_pair(x,y);
}
sort(G,G+n);
G[n]=make_pair(h,w);
for(int i=0;i<=n;i++){
int x=G[i].first-1,y=G[i].second-1;
dp[i]=C(x,y);
for(int j=0;j<i;j++){
int xx=G[i].first-G[j].first;
int yy=G[i].second-G[j].second;
LL tmp=C(xx,yy)*dp[j];
tmp%=mod;
dp[i]-=tmp;
while(dp[i]<0) dp[i]+=mod;
}
}
printf("%lld\n",dp[n]);
}