zoukankan      html  css  js  c++  java
  • Luogu 2018 秋令营 Test 2

    T1:

    题目描述

    Bob 来到了一个 $n imes m$ 的网格中,网格里有 $k$ 个豆子,第 $i$ 个豆子位于 $(x_i, y_i)$,保证没有两个豆子在同一个格子里,$(1, 1)$ 处和 $(n, m)$ 处没有豆子。

    Bob 从左上角 $(1, 1)$ 出发,目的地是右下角 $(n, m)$。每次以向右或向下走一步,也就是说他到达终点时一共会走 $n + m - 2$ 步。

    贪吃的 Bob 决定吃掉所有格子的豆子,他想知道是否存在多少条路径,使得他可以经过所有的豆子。由于答案很大,你只需要输出答案模 $10^9 + 7$ 的结果即可。

    输入输出格式

    输入格式

    第一行三个整数 $n, m, k$,意义如上所述。

    接下来 $k$ 行,每行两个整数 $x_i, y_i(1 leq x_i leq n, 1 leq y_i leq m)$,意义如上所述。2018-10-14

    输入输出样例

    入样例#1: 
    3 4 1
    1 2
    输出样例#1: 
    6
    
    输入样例#2: 
    3 4 1
    2 2
    输出样例#2: 
    6

    说明

    对于 $30\%$ 的数据,满足 $2 leq n, m leq 100$。

    对于 $60\%$ 的数据,满足 $2 leq n, m leq 1000$。

    对于 $100\%$ 的数据,满足 $2 leq n, m leq 10^5, 0 leq k leq min(n imes m - 2, 10^5)$。

     

    解题思路:

    由于要吃掉所有的豆子且只能向右向下走,那么对于每一个豆子来说,如果在当前豆子的严格左下方处仍有豆子的话肯定无解,因为不可能向左走。

    因此我们可以以每个豆子的X坐标作为第一关键字,Y坐标作为第二关键字对豆子进行排序。

    接下来考虑如何计算方案:

    可以想到方案是由乘法原理得到的,即每个当前点去往下一个点的方案数的总乘积。

    对于60%的数据我们可以用dp[i][j]表示到由(1,1)到(i,j)的方案数,直接计算即可。

    100%的数据:将dp[i][j]的表打出来可以发现是杨辉三角的变形,也就是组合数,由于数据范围较大考虑用乘法逆元计算组合数。

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define ll long long
    #define INF 0x3f3f3f3f
    #define maxn 100009
    #define maxm 1009
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ll)(ch-'0');ch=getchar();}
        return x*f;
    }
    int n,m,k,tot;
    struct node
    {
        int x,y;
    }p[maxn];
    ll ans,base;
    
    bool comp(node a,node b)
    {
        if(a.x==b.x)
            return a.y<b.y;
        return a.x<b.x; 
    }
    
    
    ll Quick_mul(ll a,ll b)
    {
        ll sum=1;
        while(b)
        {
            if(b&1)
                sum=(sum*a)%base;
            a=(a*a)%base;
            b>>=1;
        }
        return sum%base;
    }
    
    ll inv(ll x)
    {
        return Quick_mul(x,base-2)%base;
    }
    
    ll Cal(ll n,ll m)
    {
        ll a=1,b=1;
        for(ll i=n-m+1;i<=n;i++)
            a=(a*i)%base;
        for(ll j=1;j<=m;j++)
            b=(b*j)%base;
        return a*inv(b)%base;
    }
    
    int main()
    {
    //    freopen("T1.in","r",stdin);
    //    freopen("T1.out","w",stdout);
        n=read(),m=read(),k=read(),base=1e9+7;
        if(k>n+m-3)
        {
            puts("0");
            return 0;
        }
        p[0].x=1,p[0].y=1;
        for(int i=1;i<=k;i++)
            p[i].x=read(),p[i].y=read();
        sort(p+1,p+1+k,comp);        
        p[++k].x=n,p[k].y=m;
        ans=1;
        for(int i=1;i<=k;i++)
        {
            if(p[i].y<p[i-1].y)
            {
                puts("0");
                return 0;
            }
            ll x=(ll)p[i].x-p[i-1].x+1,y=(ll)p[i].y-p[i-1].y+1;
            ans=ans*Cal(x+y-2,y-1)%base; 
        }
        printf("%lld
    ",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    View Code

      

      
  • 相关阅读:
    排座椅
    关于math.h的问题
    客户调查
    排队打水
    删数游戏
    小数背包
    零件分组
    桐桐的组合
    桐桐的数学游戏
    桐桐的全排列
  • 原文地址:https://www.cnblogs.com/Dxy0310/p/9788097.html
Copyright © 2011-2022 走看看