Codeforces Round #313 (Div. 一) C. Gerald and Giant Chess(DP+组合数取模)(好题)
Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess(DP+组合数取模)(好题)
大致题意:
n,m 大小为1e5的矩形,求(1,1)点到(n,m)路径有多少中,中间有2000个不能经过点
思路:
想了好久才想出,还是太弱
首先不考虑不能经过的点,从(1,1)到任意一点(x,y)的路径的个数就是组合公式:C(x-1+y-1,x-1)
然后再考虑不能经过的点,正面艹了好久,发现搞不出来
直接从反面来,求出全集,再减去从不能经过的点到(x,y)的路径数。转移也很好
组合数取模用费马小引理之类的不懂的东西= =,用了Q神的模版
#include <iostream> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <list> #include <map> #include <set> #include <sstream> #include <string> #include <vector> #include <cstdio> #include <ctime> #include <bitset> #include <algorithm> #define SZ(x) ((int)(x).size()) #define ALL(v) (v).begin(), (v).end() #define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i) #define REP(i,n) for ( int i=1; i<=int(n); i++ ) using namespace std; typedef long long ll; #define X first #define Y second typedef pair<int,int> pii; const int N = 2000+100; const int mod = 1e9+7; ll dp[N]; int n,m,c; pii poi[N]; int f[200000+5],inv[200000+5]; int fast_pow(int a,int k) { int res=1; while(k>0) { if(k&1)res=1LL*res*a%mod; a=1LL*a*a%mod; k>>=1; } return res; } int C(int n,int k) { if(n<k)return 0; return 1LL*f[n]*inv[k]%mod*inv[n-k]%mod; } void build() { f[0]=1; for(int i=1;i<=200000;i++) f[i]=1LL*i*f[i-1]%mod; for(int i=0;i<=200000;i++) inv[i]=fast_pow(f[i],mod-2); } int main(){ build(); scanf("%d%d%d",&n,&m,&c); REP(i,c) scanf("%d%d",&poi[i].X,&poi[i].Y); sort(poi+1,poi+c+1); if(poi[c] == pii(n,m) ) { puts("0"); return 0; } poi[c+1] = pii(n,m); REP(i,c+1){ int x = poi[i].X, y = poi[i].Y; dp[i] = C(x-1+y-1,x-1); REP(j,i-1) { int lx = poi[j].X, ly = poi[j].Y; if( lx <= x && ly <= y) dp[i] = (dp[i]-dp[j]*C(x-lx+y-ly,x-lx))%mod; } } printf("%d\n",(dp[c+1]%mod+mod)%mod); }
版权声明:本文为博主原创文章,未经博主允许不得转载。