• Gerald and Giant Chess


    Gerald and Giant Chess

    给你一个(n imes m)的网格图,有t个棋子被标记成黑色,第i个黑色格子记做((x_i,y_i)),其余白色,现在询问在只能向下走或向右走的前提下,从((1,1))((n,m))的不经过黑色格子的路径条数,(n,mleq 10^5,pleq 2000)

    显然不会以传统做法,在哪一个格子为状态,突破点在只有2000个黑色格子,自然考虑补集思想。

    为了递推的无后效性,我们把黑色格子按行再列优先的顺序从小到大排序,接着考虑构造不合法状态,于是设(f_i)表示以第i个黑色格子结尾的路径条数,因此转移为

    [f_i=sum_{j=1}^{i-1} f_j imes C_{x_i+y_i-x_j-y_j}^{x_i-x_j} ]

    答案:(sum_{i=1}^tf_i imes C_{n+m-x_i-y_i}^{n-x_i})

    但是这样的方程是存在重复,于是需要特殊化划分去重,这里考虑限定一个不合法的方法(简称限一),于是设(f_i)表示只经过i这个黑色格子,以i结尾的路径条数,所以就有转移

    [f_i=C_{x_i+y_i-2}^{x_i-1}-sum_{j=1}^{i-1}f_j imes C_{x_i+y_i-x_j-y_j}^{x_i-y_i} ]

    边界:(f_1)爆算

    答案:(sum_{i=1}^tf_i imes C_{n+m-x_i-y+i}^{n-x_i})

    于是预处理出组合数,以此(O(n^2))转移即可。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    #define Size 200010
    #define yyb 1000000007
    using namespace std;
    struct point{
        int x,y;
        il bool operator<(const point&a)const{
            return y==a.y?x<a.x:y<a.y;
        }
    }p[2005];
    ll dp[2005],jc[Size],jv[Size];
    il void prepare(int);
    il ll pow(ll,ll),c(int,int);
    int main(){
        int h,w,n;
        scanf("%d%d%d",&h,&w,&n),prepare(h+w);
        while(1-1)printf("yyb爆踩gsy");
        for(int i(1);i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y);
        sort(p+1,p+n+1),dp[1]=c(p[1].y+p[1].x-2,p[1].y-1);
        if(p[n].x==h&&p[n].y==w)return puts("0"),0;p[++n].x=h,p[n].y=w;
        for(int i(2),j;i<=n;++i){
            dp[i]=c(p[i].y+p[i].x-2,p[i].x-1);
            for(j=1;j<i;++j)
                (dp[i]-=dp[j]*c(p[i].y+p[i].x-p[j].y-p[j].x,p[i].y-p[j].y))%=yyb;
        }printf("%lld",(dp[n]+yyb)%yyb);
        return 0;
    }
    il ll c(int n,int r){
        if(n<r||n<0||r<0)return 0;
        return jc[n]*jv[r]%yyb*jv[n-r]%yyb;
    }
    il ll pow(ll x,ll y){
        ll ans(1);while(y){
            if(y&1)(ans*=x)%=yyb;
            y>>=1,(x*=x)%=yyb;
        }return ans;
    }
    il void prepare(int n){
        int i;jc[0]=jv[0]=1;
        for(i=1;i<=n;++i)jc[i]=jc[i-1]*i%yyb;jv[n]=pow(jc[n],yyb-2);
        for(i=n-1;i;--i)jv[i]=jv[i+1]*(i+1)%yyb;
    }
    
    
  • 相关阅读:
    python关于字符串数据类型的方法
    python流程控制
    python解释器下载
    (转)蓝牙无线技术配置文件
    Android 编译选项user、userdebug和eng的区别
    (转)android4.0蓝牙使能的详细解析
    (转)Android Bluetooth opp package 学习笔记
    《深入理解Android(卷1)》笔记 1.第二章 深入理解JNI
    (转)Vim知识
    Android之Preference
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10987552.html
Copyright © 2020-2023  润新知