zoukankan      html  css  js  c++  java
  • HDU5852 Intersection is not allowed!

    拖了100年的题目

    There are K pieces on the chessboard. 

    The size of the chessboard is N*N. 

    The pieces are initially placed on the top cells of the board. 

    A piece located on (r, c) can be moved by one cell right to (r, c + 1) or one cell down to (r+1, c). 

    Your task is to count how many different ways to move all pieces to the given positions at the bottom of the board. 

    Furthermore, the paths of the pieces mustn’t intersect each other. 

    InputThe first line of input contains an integer T-the number of test cases. 

    Each test case begins with a line containing two integers-N(1<=N<=100000) and K(1<=K<=100) representing the size of the chessboard and the number of pieces respectively. 

    The second line contains K integers: 1<=a1<a2< …<aK<=N representing the initial positions of the pieces. That is, the pieces are located at (1, a1), (1, a2), …, (1, aK). 

    Next line contains K integers: 1<=b1<b2<…<bK<=N representing the final positions of the pieces. This means the pieces should be moved to (N, b1), (N, b2), …, (N, bK). 
    OutputPrint consecutive T lines, each of which represents the number of different ways modulo 1000000007.Sample Input

    1
    5 2
    1 2
    3 4

    Sample Output

    50

    这个题目一看到还是晕了,但是每个点好像很有规律的啊,可以容斥的

    LGV了解一下

    然后就是处理出行列式,计算行列式的值了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll MD=1e9+7;
    const int N=2e5+5,M=105;
    int s[M],e[M];
    ll a[M][M];
    ll det(int n)
    {
        ll ans=1;
        int sign=0;
        for(int i=0; i<n; i++)
        {
            for(int j=i+1; j<n; j++)
            {
                int x=i,y=j;
                while(a[y][i])
                {
                    ll t=a[x][i]/a[y][i];
                    for(int k=i; k<n; k++)
                        a[x][k]=(a[x][k]-a[y][k]*t)%MD;
                    swap(x,y);
                }
                if(x!=i)
                {
                    for(int k=0; k<n; k++)swap(a[i][k],a[x][k]);
                    sign^=1;
                }
            }
            if(a[i][i]==0)return 0;
            else ans=ans*a[i][i]%MD;
    
        }
        if(sign)ans=-ans;
        ans=(ans+MD)%MD;
        return ans;
    }
    int fac[N],inv[N];
    ll C(ll n,ll m)
    {
        if(m<0)return 0;
        return 1LL*fac[n]*inv[m]%MD*inv[n-m]%MD;
    }
    int main()
    {
        inv[0]=inv[1]=fac[0]=fac[1]=1;
        for(int i=2; i<N; i++) fac[i]=1LL*fac[i-1]*i%MD,inv[i]=1LL*inv[MD%i]*(MD-MD/i)%MD;
        for(int i=2; i<N; i++) inv[i]=1LL*inv[i-1]*inv[i]%MD;
        int n,k,t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&k);
            for(int i=0; i<k; i++)scanf("%d",&s[i]);
            for(int i=0; i<k; i++)scanf("%d",&e[i]);
            for(int i=0; i<k; i++)
                for(int j=0; j<k; j++)a[i][j]=C(n-1+e[j]-s[i],e[j]-s[i]);
            printf("%lld
    ",det(k));
        }
    }

    从(1,1)到(n,m)两条互不相交的路径条数C(n+m-4, n-2)^2-C(n+m-4,n-1)^2

    简化为从(1,2)到(n-1,m)从(2,1)到(n,m-1)两条路径

  • 相关阅读:
    【算法】Kruskal算法(解决最小生成树问题) 含代码实现
    POJ 1182 食物链 (并查集解法)(详细注释)
    APICloud关闭Key Building Resolve
    ubuntu配置国内源
    缓存穿透、缓存击穿、缓存雪崩概念及解决方案
    POST请求和GET请求的区别
    ibatis 中#和 $ 符号的区别
    自动装箱和自动拆箱理解
    回文串算法说明(带注释)
    Object 对象有哪些方法?
  • 原文地址:https://www.cnblogs.com/BobHuang/p/9761160.html
Copyright © 2011-2022 走看看