CodeForces - 560E Gerald and Giant Chess(组合数学+dp)
題目鏈接:點擊查看
題目大意:給出一個 n?mn*mn?m 的矩陣,其中有 kkk 個壞點,每次只能向右走或向下走,問從點 (1,1)(1,1)(1,1) 到點 (n,m)(n,m)(n,m) 共有多少種不同的路線
題目分析:刷知乎看到的一道題,心血來潮就想寫題了
數據范圍 n,mn,mn,m 都是 1e51e51e5 級別的,而 kkk 卻只有 200020002000,所以從壞點入手,考慮 dpdpdp 和組合數學
首先對于兩個點 (x1,y1)(x1,y1)(x1,y1) 和 (x2,y2)(x2,y2)(x2,y2) 來說,如果沒有壞點的限制,那么這兩個點之間的路線有 C(x2?x1)+(y2?y1)x2?x1C_{(x2-x1)+(y2-y1)}^{x2-x1}C(x2?x1)+(y2?y1)x2?x1? 條,下面可以分兩步進行思考,對于每個壞點 (x,y)(x,y)(x,y) 來說:
綜上所述,將所有壞點排序之后的轉移方程就是(設 f(x1,y1)(x2,y2)f_{(x1,y1)}^{(x2,y2)}f(x1,y1)(x2,y2)? 為壞點 (x1,y1)(x1,y1)(x1,y1) 到壞點 (x2,y2)(x2,y2)(x2,y2) 的方案數,dpidp_idpi? 為點 (1,1)(1,1)(1,1) 到第 iii 個壞點的方案數):
dpi=f(1,1)(pi.x,pi.y)?[pj.x<=pi.x&&pj.y<=pi.y]?dpj?f(pi.x,pi.y)(pj.x,pj.y)dp_i=f_{(1,1)}^{(p_i.x,p_i.y)} \\ -[p_j.x<=p_i.x\ \&\&\ p_j.y<=p_i.y]*dp_j*f_{(p_i.x,p_i.y)}^{(p_j.x,p_j.y)} dpi?=f(1,1)(pi?.x,pi?.y)??[pj?.x<=pi?.x?&&?pj?.y<=pi?.y]?dpj??f(pi?.x,pi?.y)(pj?.x,pj?.y)?
將點 (n,m)(n,m)(n,m) 設為第 k+1k+1k+1 個壞點,那么答案自然就是 dpk+1dp_{k+1}dpk+1? 了
代碼:
// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; const int mod=1e9+7; struct Point {int x,y;void input() {read(x),read(y);}bool operator<(const Point& t)const {if(x!=t.x) {return x<t.x;}return y<t.y;} }p[N]; LL dp[N],fac[N],inv[N]; LL q_pow(LL a,LL b) {LL ans=1;while(b) {if(b&1) {ans=ans*a%mod;}a=a*a%mod;b>>=1;}return ans; } LL C(int n,int m) {if(n<m) {return 0;}return fac[n]*inv[m]%mod*inv[n-m]%mod; } void init() {fac[0]=1;for(int i=1;i<N;i++) {fac[i]=fac[i-1]*i%mod;}inv[N-1]=q_pow(fac[N-1],mod-2);for(int i=N-2;i>=0;i--) {inv[i]=inv[i+1]*(i+1)%mod;} } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n,m,k;read(n),read(m),read(k);for(int i=1;i<=k;i++) {p[i].input();}p[++k]={n,m};sort(p+1,p+1+k);for(int i=1;i<=k;i++) {dp[i]=C((p[i].x-1)+(p[i].y-1),(p[i].x-1));for(int j=1;j<i;j++) {if(p[i].x>=p[j].x&&p[i].y>=p[j].y) {dp[i]=(dp[i]-dp[j]*C((p[i].x-p[j].x)+(p[i].y-p[j].y),p[i].x-p[j].x)%mod+mod)%mod;}}}write(dp[k]);return 0; }總結
以上是生活随笔為你收集整理的CodeForces - 560E Gerald and Giant Chess(组合数学+dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++中std::set自定义去重和排序
- 下一篇: FZU - 2042 The Mad M