HDU 5852 Intersection is not allowed!

38 篇文章 0 订阅
17 篇文章 0 订阅

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
  
  
1 5 2 1 2 3 4
 

Sample Output
  
  
50
 

Author
金策工业综合大学(DPRK)
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:  6032 6031 6030 6029 6028
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

组合数问题+行列式求值+逆元~

思路见:http://blog.csdn.net/v5zsq/article/details/52419187

建议计算过程开long long,容易写。

组合数一定要先判掉m>n的情况,直接输出0!


#include<cstdio>
#include<iostream>
using namespace std;
#define ll long long
#define mod 1000000007

ll t,n,m,a[101][102],b[101],c[101],sheng[200001],ni[200001],ans;

ll read()
{
	ll x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}

ll mi(ll u,ll v)
{
	ll now=1;u%=mod;
	for(;v;v>>=1,u=(ll)u*u%mod) if(v&1) now=(ll)now*u%mod;
	return now;
}

ll cc(ll n,ll m)
{
	if(m>n) return 0;
	return (ll)sheng[n]*ni[m]%mod*ni[n-m]%mod;
}

ll cal(ll n)
{
	ll ans=1,pos=-1;
	for(ll i=1;i<=n;i++)
	{
		pos=-1;
		for(ll j=i;j<=n;j++) if(a[j][i])
		{
			pos=j;break;
		}
		if(pos==-1) return 0;
		if(pos!=i) for(ll j=i;j<=n;j++) swap(a[pos][j],a[i][j]);
		ll now=mi(a[i][i],mod-2);
		for(ll j=i+1;j<=n;j++)
		  if(a[j][i])
		  {
			  ans=ans*now%mod;
			  for(ll k=i+1;k<=n;k++) a[j][k]=((a[j][k]*a[i][i]%mod-a[i][k]*a[j][i]%mod)+mod)%mod;
			  a[j][i]=0;
		  }
	}
	for(ll i=1;i<=n;i++) ans=ans*a[i][i]%mod;
	return ans;
}

int main()
{
	t=read();sheng[0]=1;ni[0]=1;
	for(int i=1;i<=200000;i++) sheng[i]=(ll)sheng[i-1]*i%mod,ni[i]=mi(sheng[i],mod-2);
	while(t--)
	{
		n=read();m=read();
		for(int i=1;i<=m;i++) b[i]=read();
		for(int i=1;i<=m;i++) c[i]=read();
		for(int i=1;i<=m;i++)
		  for(int j=1;j<=m;j++) a[i][j]=cc(n-1-b[j]+c[i],n-1);
		ans=cal(m);
		printf("%lld\n",ans);
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值