zoukankan      html  css  js  c++  java
  • HDU 5852 Intersection is not allowed!(LGV定理行列式求组合数)题解

    题意:有K个棋子在一个大小为N×N的棋盘。一开始,它们都在棋盘的顶端,它们起始的位置是 (1,a1),(1,a2),...,(1,ak) ,它们的目的地是 (n,b1),(n,b2),...,(n,bk)。

     一个位于 (r,c) 的棋子每一步只能向右走到 (r,c+1) 或者向下走到 (r+1,c) 。

    我们把 i 棋子从 (1,ai) 走到 (n,bi) 的路径记作 pi 。

    你的任务是计算有多少种方案把n个棋子送到目的地,并且对于任意两个不同的棋子 i,j ,使得路径 pi 与 pj 不相交(即没有公共点)。

    思路:这里有一个结论,n个起点到n个终点的不相交路径的种数为:每个起点到每个终点的可能数组成的n*n的矩阵的行列式。

    即求上矩阵行列式,其中e(ai,bi)代表从ai起点到bi终点的可能路径数量。

    行列式求解用高斯消元。提交要用G++,C++一直超时emmmm

    参考:HDU 5852:Intersection is not allowed!(行列式+逆元求组合数)

    代码:

    #include<set>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    typedef long long ll;
    using namespace std;
    const int maxn = 1e5 + 10;
    const int seed = 131;
    const ll MOD = 1000000007;
    const int INF = 0x3f3f3f3f;
    int a[maxn], b[maxn];
    ll e[105][105];
    ll fac[maxn << 1], niYuan[maxn << 1];
    ll pmul(ll a, ll b){
        ll ans = 1;
        while(b){
            if(b & 1) ans = ans * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return ans;
    }
    ll C(int n, int m){
        ll ret = fac[n] * niYuan[m] % MOD;
        return ret * niYuan[n - m] % MOD;
    }
    void initFac(){
        fac[0] = niYuan[0] = 1;
        for(ll i = 1; i <= 200005; i++){
            fac[i] = fac[i - 1] * i % MOD;
            niYuan[i] = pmul(fac[i], MOD - 2);
        }
    }
    ll guass(int n){
        ll ans = 1, f = 1;  //行列式和符号位
        for(int i = 1; i <= n; i++){
            for(int j = i + 1; j <= n; j++){
                int x = i, y = j;
                while(e[y][i]){
                    ll t = e[x][i] / e[y][i];
                    for(int k = i; k <= n; k++)
                        e[x][k] = (e[x][k] - e[y][k] * 1LL * t % MOD) % MOD;
                    swap(x,y);
                }
                if(x != i){
                    for(int k = 1; k <= n; k++)
                        swap(e[i][k], e[j][k]);
                    f = -f;
                }
            }
            ans = ans * e[i][i] % MOD;
            if(ans == 0) return 0;
        }
        return (ans * f + MOD) % MOD;
    }
    int main(){
        initFac();
        int t;
        scanf("%d", &t);
        while(t--){
            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++){
                    if(b[j] >= a[i]){
                        e[i][j] = C(n - 1 + b[j] - a[i], b[j] - a[i]);
                    }
                    else e[i][j] = 0;
                }
            }
            printf("%lld
    ", guass(k));
        }
        return 0;
    }
  • 相关阅读:
    比尔盖茨,乔布斯,扎克伯格,Linus 等巨佬的办公桌
    快速从 Windows 切换到 Linux 环境
    海外开发者账号上架总结
    Chrome 浏览器对标签进行整理和分组的功能太棒了!
    最受嵌入式软件工程师青睐的系统
    我最喜欢的云 IDE 有哪些?
    前端zip包下载
    el-upload上传组件(隐藏上传按钮/隐藏文件删除标记)
    滚动条样式
    使用ul标签制作简单的菜单(vue模板)
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10028898.html
Copyright © 2011-2022 走看看