zoukankan      html  css  js  c++  java
  • HDU 5852 Intersection is not allowed! ( 2016多校9、不相交路径的方案、LGV定理、行列式计算 )

    题目链接

    题意 : 给定方格中第一行的各个起点、再给定最后一行与起点相对应的终点、问你从这些起点出发到各自的终点、不相交的路径有多少条、移动方向只能向下或向右

    分析 :

    首先对于多起点和多终点的不相交路径、有一个LGV定理

    实际上就是 n^2 构造矩阵、再计算其行列式

    矩阵的构造方法可以看看这个 ==> Click here

    那么接下来就是确定各自路径的方案数了

    这是一个经典问题

    这里需要求解组合数、用预处理阶乘逆元的方法即可求出

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    const int Comb_Maxn = 2e5 + 10;
    const LL mod = 1e9 + 7;
    
    LL Fac_inv[Comb_Maxn];
    LL Fac[Comb_Maxn];
    
    inline void Comb_init()
    {
        Fac_inv[0] = Fac[0] = 1;
        Fac_inv[1] = 1;
    
        for(int i=1; i<Comb_Maxn; i++)
            Fac[i] = Fac[i-1] * (LL)i % mod;
    
        for(int i=2; i<Comb_Maxn; i++)
            Fac_inv[i] = (LL)(mod - mod / i) * Fac_inv[mod % i] % mod;
    
        for(int i=1; i<Comb_Maxn; i++)
            Fac_inv[i] = Fac_inv[i-1] * Fac_inv[i] % mod;
    }
    
    LL Comb(int n, int m)
    { return Fac[n] * Fac_inv[m] % mod * Fac_inv[n-m] % mod; }
    
    const int maxm = 1e2;
    LL Mat[maxm+5][maxm+5];
    int turn,n;
    void gcd(LL a,LL b,LL &d,LL &x,LL &y)
    {
        if(!b) d=a,x=1,y=0;
        else{
            ++turn;
            gcd(b,a%b,d,y,x);
            y-=x*(a/b);
        }
    }
    LL det(LL n)
    {
        LL tmp1[maxm+5],tmp2[maxm+5];
        LL ans=1;
        for(int i=1;i<=n;++i){
            for(int j=i+1;j<=n;++j){
                if(Mat[j][i]!=0){
                    LL A=Mat[i][i],B=Mat[j][i],d,x,y;
                    turn=0;
                    gcd(A,B,d,x,y);
                    for(int k=1;k<=n;++k) tmp1[k]=Mat[i][k],tmp2[k]=Mat[j][k];
                    for(int k=1;k<=n;++k) Mat[i][k]=(x*tmp1[k]+y*tmp2[k])%mod;
                    A/=d,B/=d;
                    if(turn&1) x=B,y=-A,ans=-ans%mod;else x=-B,y=A;
                    for(int k=1;k<=n;++k) Mat[j][k]=(x*tmp1[k]+y*tmp2[k])%mod;
                }
            }
            ans=ans*Mat[i][i]%mod;
        }
        if(ans<0) ans+=mod;
        return ans;
    }
    
    int A[maxm], B[maxm];
    int main(void)
    {
        Comb_init();
        int nCase;
        scanf("%d", &nCase);
        while(nCase--){
            int n, k;
            scanf("%d %d", &n, &k);
            for(int i=1; i<=k; i++) scanf("%d", &A[i]);
            for(int i=1; i<=k; i++) scanf("%d", &B[i]);
            for(int i=1; i<=k; i++){
                for(int j=1; j<=k; j++){
                    int a, b;
                    a = n-1+B[j]-A[i];
                    b = n-1;
                    if(a < b) Mat[i][j] = 0;
                    else if(a < 0 || b < 0) Mat[i][j] = 0;
                    else Mat[i][j] = Comb(a, b);
                }
            }
    
            printf("%lld
    ", det(k) % mod);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    MyBatis学习之输入输出类型
    MyBatis学习之多表查询
    javascript学习之this
    Elasticsearch学习之Java操作1
    CSS学习之定位
    CSS学习之浮动
    CSS学习之盒子模型
    java学习之导出Excel
    转载:手把手教你做iOS推送
    拳头公司聊天服务架构:服务器篇
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/9921084.html
Copyright © 2011-2022 走看看