行列式求值+逆元_____Intersection is not allowed!( hdu 5852 2016多校第九场)

来源:互联网 发布:sip电话软件 编辑:程序博客网 时间:2024/06/02 02:19

Problem Description
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.
 

Input
The 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).
 

Output
Print consecutive T lines, each of which represents the number of different ways modulo 1000000007.
 

Sample Input
15 21 23 4
 

Sample Output
50
 


题意:

给你两个长度为K的数列x[ ] ,y [ ] 。表示在N*N的棋盘,最开始有K个棋子在(1,x[1] ) ,(1,x[2] ),,,,,,(1,x[K])处。要将K个棋子移动到(N,y[1] ) ,(N,y[2] ),,,,,,(N,y[K])处.并且每个棋子的路径不能相交。求移动种数。只能向下和向右移动。


分析:这里有个结论,K个点在有向无环图中移动到另外K个点。每个点移动路径不能相交。移动种数为。每个起点移动到每个终点的全部移动种数组成一个K*K行列式。行列式的值就是所求。


代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define eps 1e-6typedef long long ll;const ll mod = 1e9+7;const int N = 2e5+10;ll inv[N] = {1,1};  //inv[i] i的逆元。ll fac[N] = {1,1};    // fac[i] i!%modll facv[N] = {1,1};   // facv[i] i!的逆元void init(){    for(int i = 2 ; i < N ; i ++)        inv[i] = (mod-mod/i) * inv[mod%i] % mod;    for(int i = 2 ; i < N ; i ++)        facv[i] = facv[i-1] * inv[i] % mod;    for(int i = 2 ; i < N ; i ++)        fac[i] = fac[i-1]*i % mod;}ll C(ll n,ll m){    if(m < 0) return 0;    return fac[n]*facv[m]%mod*facv[n-m]%mod;}int s[110],e[110];ll a[110][110];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++)//当前之后的每一行,因为每一行的当前第一个数要转化成0(想想线性代数中行列式的计算)        {            int x=i,y=j;            while(a[y][i])//利用gcd的方法,不停地进行辗转相除            {                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)%mod;                swap(x,y);            }            if(x!=i)//奇数次交换,则D=-D'整行交换            {                for(int k=0;k<n;k++)                    swap(a[i][k],a[x][k]);                sign^=1;            }        }        if(a[i][i]==0)//斜对角中有一个0,则结果为0        {            return 0;        }        else            ans=ans*a[i][i]%mod;    }    if(sign!=0)        ans*=-1;    if(ans<0)        ans+=mod;    return ans;}int main(){    int n,k,t;    init();    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\n",det(k));    }    return 0;}







0 0
原创粉丝点击