码迷,mamicode.com
首页 > 其他好文 > 详细

【CF559C】Gerald and Giant Chess 题解(动态规划+组合数学)

时间:2020-09-18 00:04:18      阅读:31      评论:0      收藏:0      [点我收藏+]

标签:复杂度   limits   动态   space   sum   long   计算   不能   efi   

题目大意:给定一个H*W的棋盘,棋盘上只有N个格子是黑色的,其他格子都是白色的。在棋盘左上角有一个卒,每一步可以向右或者向下移动一格,并且不能移动到黑色格子中。求这个卒从左上角移动到右下角,一共有多少种可能的路线。$h,w\leq 10^5,k\leq 2000$。答案对$1e9+7$取模。

看到数据范围可以看出此题的时间复杂度和$k$有关,自然就想到每个障碍对答案产生了多少贡献。

考虑路径的组合意义:从左下角走到右下角,先不考虑有障碍的情况,显然是$\binom{n+m-2}{m-1}$,表示一共走$n+m-2$步,其中$m-1$步是向右走的。

现在考虑有障碍的情况:先将所有障碍以$x$为第一关键字,$y$以为第二关键字排序。我们设$f_i$表示从右下角走到第$i$个障碍的方案数。如果不考虑在它右下方的那些障碍,那么答案是$\binom{n+m-x_i-y_i}{m-y_i}$。有些路径可能经过在它右下方的障碍,所以要减去它们对答案的影响。所以有:

$f_i=\binom{n+m-x_i-y_i}{y-x_i}-\sum\limits_{j=i+1}^k f_j*\binom{x_j+y_j-x_i-y_i}{y_j-y_i}$

最终答案为:

$ans=\binom{n+m-2}{m-1}-\sum\limits_{i=1}^k f_i*\binom{x_i+y_i-2}{y_i-1}$

组合数可以$O(n)$预处理逆元,$O(1)$计算。时间复杂度$O(k^2+n\log n)$。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int mod=1e9+7;
const int maxn=500005;
int n,m,k,inv[maxn],fac[maxn],ans,f[maxn];
struct node
{
    int x,y;
}a[maxn];
inline bool cmp(node x,node y){return x.x==y.x?x.y<y.y:x.x<y.x;}
inline int calc(int x,int y)
{
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch==-) f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
inline int qpow(int x,int y)
{
    int res=1;
    while(y)
    {
        if (y&1) res=(res*x)%mod;
        x=(x*x)%mod;
        y>>=1;
    }
    return res;
}
signed main()
{
    n=read();m=read();k=read();
    fac[0]=1;
    for (int i=1;i<=n+m;i++) fac[i]=(fac[i-1]*i)%mod;
    inv[n+m]=qpow(fac[n+m],mod-2);
    for (int i=n+m-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod; 
    for (int i=1;i<=k;i++) a[i].x=read(),a[i].y=read();
    sort(a+1,a+k+1,cmp);
    ans=calc(n+m-2,m-1);
    for (int i=k;i>=1;i--)
    {
        f[i]=calc(n+m-a[i].x-a[i].y,m-a[i].y);f[i]%=mod;
        for (int j=i+1;j<=k;j++)
            f[i]=(f[i]-f[j]*calc(a[j].x+a[j].y-a[i].x-a[i].y,a[j].y-a[i].y)%mod+mod)%mod;
        ans=(ans-f[i]*calc(a[i].x+a[i].y-2,a[i].y-1)%mod+mod)%mod;
    }
    printf("%lld",ans);
    return 0;
}

 

【CF559C】Gerald and Giant Chess 题解(动态规划+组合数学)

标签:复杂度   limits   动态   space   sum   long   计算   不能   efi   

原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13661829.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!