其他分享
首页 > 其他分享> > [CF559C] Gerald and Giant Chess - 计数dp

[CF559C] Gerald and Giant Chess - 计数dp

作者:互联网

Description

给定一个 \(H \times W\) 的棋盘,有 \(N\) 个障碍格子,棋子每次可以向右或者向下移动一步,求从左上角到右下角有多少种不同的路线。\(N \le 2000\)

Solution

由于 \(N\) 较小,考虑 dp,设 \(f[i]\) 表示走到第 \(i\) 个障碍点(且之前不经过其它任何障碍点)的方案数,则

\[f[i]=g(x_i,y_i) - \sum_{j \to i} g(x_i-x_j+1,y_i-y_j+1 )\cdot f[j] \]

其中 \(j \to i \Leftrightarrow x_j \le x_i \and y_j \le y_i\),\(g(x,y)\) 表示无障碍情况下 \((1,1) \to (x,y)\) 的方案数,有

\[g(x,y)=\binom {x+y-2}{x-1} \]

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 2005;
const int M = 200005;
const int mod = 1e9+7;

int f[N],frac[M],ifrac[M],h,w,x[N],y[N],n;

struct pii
{
    int x,y;
    bool operator < (const pii &obj)
    {
        if(x==obj.x) return y<obj.y;
        return x<obj.x;
    }
} buf[N];

int qpow(int p,int q)
{
    return (q&1 ? p : 1) * (q ? qpow(p*p%mod,q>>1) : 1) % mod;
}

int inv(int p)
{
    return qpow(p,mod-2);
}

int nCr(int n,int m)
{
    return frac[n]*ifrac[m]%mod*ifrac[n-m]%mod;
}

int g(int x,int y)
{
    return nCr(x+y-2,x-1);
}

signed main()
{
    ios::sync_with_stdio(false);

    cin>>h>>w>>n;
    for(int i=1;i<=n;i++) cin>>x[i]>>y[i];

    frac[0]=ifrac[0]=1;
    for(int i=1;i<M;i++) frac[i]=frac[i-1]*i%mod;
    for(int i=1;i<M;i++) ifrac[i]=inv(frac[i]);

    for(int i=1;i<=n;i++) buf[i].x=x[i], buf[i].y=y[i];
    sort(buf+1,buf+n+1);
    for(int i=1;i<=n;i++) x[i]=buf[i].x, y[i]=buf[i].y;

    f[0]=1;
    x[0]=y[0]=1;
    x[n+1]=h;
    y[n+1]=w;
    for(int i=1;i<=n+1;i++)
    {
        f[i]=g(x[i],y[i]);
        for(int j=1;j<i;j++)
        {
            if(x[i]>=x[j] && y[i]>=y[j]) f[i]-=g(x[i]-x[j]+1,y[i]-y[j]+1)*f[j];
            f[i]%=mod;
            f[i]+=mod;
            f[i]%=mod;
        }
    }

    cout<<f[n+1]<<endl;
}

标签:Giant,le,return,int,Gerald,ifrac,CF559C,const,mod
来源: https://www.cnblogs.com/mollnn/p/13589059.html