• UVALive


    题目链接:

    http://acm.hust.edu.cn/vjudge/problem/96344

    Punching Robot

    Time Limit: 1000MS
    64bit IO Format: %lld & %llu

    题意

    在n*m的棋盘上有k个障碍物,并且这k个障碍物周围8个格子也都是障碍物,问从(1,1)到(n,m)总共有多少种不经过障碍物任何的走法(每次只能向下走或者向右走。

    题解

    这题和之前的一道题基本相同:点这里
    由于给的质数比较小,所以不能保证互质(比如说mod与mod就不会互质了),所以求逆的时候会出问题,可以考虑求阶乘的时候单独把997这个因子全部提出来,并且记录下个数,单独讨论一下就可以做了。

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxn=2e6+10;
    const int mod=997;
    
    int n,m,k;
    LL dp[111],fac[maxn];
    int num[maxn];
    VPII robot;
    
    void gcd(LL a,LL b,LL& d,LL& x,LL& y){
        if(!b){ d=a; x=1; y=0; }
        else{ gcd(b,a%b,d,y,x); y-=x*(a/b); }
    }
    
    LL Inv(LL a,int mod){
        LL d,x,y;
        gcd(a,mod,d,x,y);
        return d==1?(x+mod)%mod:-1;
    }
    
    LL get_C(int n,int m){
        if(n<m||n<0||m<0) return 0;
        if(num[n]!=num[m]+num[n-m]) return 0;
        return fac[n]*Inv(fac[m]*fac[n-m]%mod,mod)%mod;
    }
    
    LL calc(int i,int j){
        int n=robot[j].X-robot[i].X;
        int m=robot[j].Y-robot[i].Y;
        if(n<0||m<0) return 0;
        return get_C(n+m,n);
    }
    
    void pre(){
        clr(num,0);
        fac[0]=1;
        for(int i=1;i<maxn;i++){
            int x=i;
            num[i]+=num[i-1];
            while(x%mod==0){
                x/=mod;
                num[i]++;
            }
            fac[i]=fac[i-1]*x%mod;
        }
    }
    
    void init(){
        clr(dp,0);
        robot.clear();
    }
    
    int main() {
        pre();
        int tc,kase=0;
        scf("%d",&tc);
        while(tc--){
            scf("%d%d%d",&n,&m,&k);
            init();
            int su=1;
            for(int i=1;i<=k;i++){
                int x,y;
                scf("%d%d",&x,&y);
                for(int dx=-1;dx<=1;dx++){
                    for(int dy=-1;dy<=1;dy++){
                        int a=x+dx,b=y+dy;
                        robot.pb(mkp(a,b));
                        if(a==1&&b==1||a==n&&b==m){
                            su=0;
                        }
                    }
                }
            }
            if(!su){ puts("0"); continue; }
            robot.pb(mkp(1,1));
            robot.pb(mkp(n,m));
            sort(robot.begin(),robot.end());
    
            for(int i=1;i<robot.sz();i++){
                dp[i]=calc(0,i);
                for(int j=1;j<i;j++){
                    dp[i]=(dp[i]-dp[j]*calc(j,i)%mod)%mod;
                }
                dp[i]=(dp[i]+mod)%mod;
            }
            printf("Case #%d: %lld
    ",++kase,dp[robot.sz()-1]);
        }
        return 0;
    }
    
    //end-----------------------------------------------------------------------
    

    其实直接上卢卡斯就不会有不互质的困扰啦!(跑的更快!)

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxn=2e6+10;
    const int mod=997;
    
    int n,m,k;
    LL dp[111],fac[mod+10],facinv[mod+10],inv[mod+10];
    VPII robot;
    
    LL get_C(int n,int m){
        if(n<m||n<0||m<0) return 0;
        return fac[n]*facinv[n-m]%mod*facinv[m]%mod;
    }
    
    LL Lucas(LL n,LL m,LL p){
        if(m==0) return 1LL;
        return get_C(n%p,m%p)*Lucas(n/p,m/p,p)%p;
    }
    
    LL calc(int i,int j){
        int n=robot[j].X-robot[i].X;
        int m=robot[j].Y-robot[i].Y;
        if(n<0||m<0) return 0;
        return Lucas(n+m,n,mod);
    }
    
    void pre(){
        fac[0]=fac[1]=1;
        facinv[0]=facinv[1]=1,inv[1]=1;
        for(int i=2;i<mod;i++){
            fac[i]=fac[i-1]*i%mod;
            inv[i]=(mod-mod/i)*inv[mod%i]%mod;
            facinv[i]=facinv[i-1]*inv[i]%mod;
        }
    }
    
    void init(){
        clr(dp,0);
        robot.clear();
    }
    
    int main() {
        pre();
        int tc,kase=0;
        scf("%d",&tc);
        while(tc--){
            scf("%d%d%d",&n,&m,&k);
            init();
            int su=1;
            for(int i=1;i<=k;i++){
                int x,y;
                scf("%d%d",&x,&y);
                for(int dx=-1;dx<=1;dx++){
                    for(int dy=-1;dy<=1;dy++){
                        int a=x+dx,b=y+dy;
                        robot.pb(mkp(a,b));
                        if(a==1&&b==1||a==n&&b==m){
                            su=0;
                        }
                    }
                }
            }
            if(!su){ puts("0"); continue; }
            robot.pb(mkp(1,1));
            robot.pb(mkp(n,m));
            sort(robot.begin(),robot.end());
    
            for(int i=1;i<robot.sz();i++){
                dp[i]=calc(0,i);
                for(int j=1;j<i;j++){
                    dp[i]=(dp[i]-dp[j]*calc(j,i)%mod)%mod;
                }
                dp[i]=(dp[i]+mod)%mod;
            }
            printf("Case #%d: %lld
    ",++kase,dp[robot.sz()-1]);
        }
        return 0;
    }
    
    //end-----------------------------------------------------------------------
  • 相关阅读:
    线段树练习两题
    DP+单调队列 codevs 1748 瑰丽华尔兹(还不是很懂具体的代码实现)
    线段树和树状数组问题补充
    一些常见的优化:读入优化,滚动数组
    单调队列应用--BZOJ 3831 Little Bird
    单调队列练习之广告印刷
    详解--单调队列 经典滑动窗口问题
    数据结构--栈 codevs 1107 等价表达式
    离散化+线段树 POJ 3277 City Horizon
    求次短路 codevs 1269 匈牙利游戏
  • 原文地址:https://www.cnblogs.com/fenice/p/5836089.html
Copyright © 2020-2023  润新知