【Codeforces Round #313 (Div. 1) C】 CodeForces 559C Gerald and Giant Chess

175 篇文章 0 订阅
87 篇文章 1 订阅

Description

Giant chess is quite common in Geraldion. We will not delve into the
rules of the game, we’ll just say that the game takes place on an
h × w field, and it is painted in two colors, but not like in chess.
Almost all cells of the field are white and only some of them are
black. Currently Gerald is finishing a game of giant chess against his
friend Pollard. Gerald has almost won, and the only thing he needs to
win is to bring the pawn from the upper left corner of the board,
where it is now standing, to the lower right corner. Gerald is so
confident of victory that he became interested, in how many ways can
he win?

The pawn, which Gerald has got left can go in two ways: one cell down
or one cell to the right. In addition, it can not go to the black
cells, otherwise the Gerald still loses. There are no other pawns or
pieces left on the field, so that, according to the rules of giant
chess Gerald moves his pawn until the game is over, and Pollard is
just watching this process.

Input

The first line of the input contains three integers: h, w, n — the
sides of the board and the number of black cells
(1 ≤ h, w ≤ 105, 1 ≤ n ≤ 2000).

Next n lines contain the description of black cells. The i-th of these
lines contains numbers ri, ci (1 ≤ ri ≤ h, 1 ≤ ci ≤ w) — the number of
the row and column of the i-th cell.

It is guaranteed that the upper left and lower right cell are white
and all cells in the description are distinct.

Output

Print a single line — the remainder of the number of ways to move
Gerald’s pawn from the upper left to the lower right corner modulo
109 + 7.

计数类dp。
用总方案数减去经过黑格子的方案个数,得到的就是答案。
但是经过黑格子的路径可能经过很多个黑格子,导致重复计算。
于是可以设dp[i]表示从起点到黑点i的合法路径个数,合法路径是说这之前不经过其他黑点。
那么dp[i]=(起点走到点i的路径总数)-∑(dp[j]*(点j到点i的路径总数),点j在点i的左上方)
可以把终点当成一个黑点,他的dp就是答案。
解决两个问题:
1.保证计算点i时,所有在点i左上方的点都计算过。可以通过坐标排序解决。
2.求两点之间的路径总数。
设两点的横、纵坐标之差分别为x,y。
路径总数=C(x,x+y)=(x+y)!/(x!y!)。
因为有除法,所以需要用乘法逆元。
预处理出1..20000的阶乘和其逆元即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long p=1000000007;
long long dp[2010],jc[200100],vjc[200100];
struct node
{
    int x,y;
    bool operator < (const node &a) const
    {
        return (x<a.x)||(x==a.x&&y<a.y);
    }
}a[2010];
void eu(long long a,long long b,long long &x,long long &y)
{
    if (!b)
    {
        x=1;
        y=0;
    }
    else
    {
        eu(b,a%b,y,x);
        y-=x*(a/b);
    }
}
void init()
{
    int i;
    vjc[0]=jc[0]=1;
    long long x;
    for (i=1;i<=200010;i++)
    {
        jc[i]=(jc[i-1]*i)%p;
        eu(jc[i],p,vjc[i],x);
        vjc[i]%=p;
        vjc[i]+=p;
        vjc[i]%=p;
    }
}
long long c(int x,int y)
{
    return jc[y]*vjc[x]%p*vjc[y-x]%p;
}
int main()
{
    int i,j,k,m,n,q,x,y,z,h,w;
    init();
    scanf("%d%d%d",&h,&w,&n);
    n++;
    for (i=1;i<n;i++)
      scanf("%d%d",&a[i].x,&a[i].y);
    a[n].x=h;
    a[n].y=w;
    sort(a+1,a+n+1);
    for (i=1;i<=n;i++)
    {
        dp[i]=c(a[i].x-1,a[i].x+a[i].y-2);
        for (j=1;j<i;j++)
          if (a[j].y<=a[i].y)
            dp[i]=((dp[i]-dp[j]*c(a[i].x-a[j].x,a[i].x-a[j].x+a[i].y-a[j].y)%p)+p)%p;
    }
    printf("%lld\n",dp[n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值