HDU5852 Intersection is not allowed!

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

 

数学问题 容斥 矩阵行列式 脑洞题

假如只有一个起点一个终点,显然是一个基本的组合数问题,从所有步数中选n-1步向下走,方案为 $ ans = C(b-a+n-1,n-1) $

如果有两个起点两个终点,则是总方案数减去路径交叉的方案数。路径相交可以理解为两人交换了目的地,所以方案为

  $ ans = C(b_1-a_1+n-1,n-1)*C(b_2-a_2+n-1,n-1) - C(b_1-a_2+n-1,n-1)*C(b_2-a_1+n-1,n-1)$

显然枚举起点和终点有几对逆序对,可以容斥计算出答案,显然这样TLE了

但这个逆序对数量决定加还是减的容斥可以让我们联想到另一个东西——矩阵行列式。

从矩阵的每一行选一列,将选的每一个位置的值乘起来,乘以(-1)^(逆序对数),即是这一部分对行列式值的贡献,所有的选法的贡献叠加起来,就是矩阵行列式的值。

那么我们只要将每个(u to v)的关系用矩阵表示,再求矩阵行列式的值就是答案了。

 1 /*by SilverN*/
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<cstring>
 7 #define LL long long
 8 using namespace std;
 9 const int mxn=200010;
10 const int mod=1e9+7;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
15     return x*f;
16 }
17 int fac[mxn],inv[mxn];
18 void init(){
19     fac[0]=fac[1]=1;inv[0]=inv[1]=1;
20     for(int i=2;i<mxn;i++){
21         fac[i]=(LL)fac[i-1]*i%mod;
22         inv[i]=((-mod/i*(LL)inv[mod%i])%mod+mod)%mod;
23     }
24     for(int i=2;i<mxn;i++)inv[i]=(LL)inv[i]*inv[i-1]%mod;
25     return;
26 }
27 int ksm(int a,int k){
28     int res=1;
29     while(k){
30         if(k&1)res=(LL)res*a%mod;
31         a=(LL)a*a%mod;
32         k>>=1;
33     }
34     return res;
35 }
36 int f[105][105];
37 int Gauss(int n){
38     int ft=1;
39     for(int i=1;i<=n;i++){
40         if(!f[i][i]){
41             int p=i;
42             for(int j=i+1;j<=n;j++)if(f[j][i]){p=j;break;}
43             if(p==i)return 0;
44             for(int j=i;j<=n;i++)swap(f[i][j],f[p][j]);
45             ft=-ft;
46         }
47         int IV=ksm(f[i][i],mod-2);
48         for(int j=i+1;j<=n;j++){
49             int tmp=(LL)f[j][i]*IV%mod;
50             for(int k=i;k<=n;k++){
51                 f[j][k]=((LL)f[j][k]-(LL)tmp*f[i][k])%mod;
52             }
53         }
54     }
55     int res=ft;
56     for(int i=1;i<=n;i++){
57         res=(LL)res*f[i][i]%mod;
58     }
59     return (res+mod)%mod;
60 }
61 int n,K;
62 int a[mxn],b[mxn];
63 int C(int n,int m){
64     if(n<m)return 0;
65     return (LL)fac[n]*inv[m]%mod*inv[n-m]%mod;
66 }
67 int path(int x,int y){
68     return (LL)C(b[y]-a[x]+n-1,n-1);
69 }
70 void solve(){
71     memset(f,0,sizeof f);
72     for(int i=1;i<=K;i++){
73         for(int j=1;j<=K;j++){
74             f[i][j]=path(i,j);
75         }
76     }
77     int ans=Gauss(K);
78     printf("%d\n",ans);
79     return;
80 }
81 int main(){
82 //    freopen("in.txt","r",stdin);
83     init();
84     int T=read(),i;
85     while(T--){
86         n=read();K=read();
87         for(i=1;i<=K;i++)a[i]=read();
88         for(i=1;i<=K;i++)b[i]=read();
89         solve();
90     }
91     return 0;
92 }

 

posted @ 2017-06-12 19:23  SilverNebula  阅读(140)  评论(0编辑  收藏  举报
AmazingCounters.com