[JZOJ6244]【NOI2019模擬2019.7.1】Trominoes 【計數】

Description

在這裏插入圖片描述
n,m<=10000

Solution

考慮暴力輪廓線DP,按順序放骨牌
顯然輪廓線長度爲N+M
輪廓線也是單調的
1表示向上,0表示向右
N個1,M個0
只能放四種骨牌
四種轉移寫出來,就是

1000 0001
1110 0111
1010 0011
1100 0101

相當與一個1和後面3格的一個0換過來,中間不變
把模3相同的分組, 轉換成只換相鄰的10
再把它看作輪廓線,相當與每次只能放1×1的骨牌,問拓撲序個數
利用楊氏矩陣的鉤子定理
就是矩陣大小的階乘除以每個位置向右向下的位置個數和之積
最後再乘個組合數表示選的順序
此時我們發現組合數約掉了,只剩下一個n×m的階乘
直接計算即可。

Code

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
typedef long long LL;
const int mo=1000000007;
using namespace std;
int n,m,r,c[3][2],js[33333333];
LL ksm(LL k,LL n)
{
	LL s=1;
	for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
	return s;
}
LL calc(int p)
{
	int n=c[p][0],m=c[p][1];
	LL s=1;
	fo(i,1,n+m-1)
	{
		LL nv=ksm(i,mo-2),ct=max(0,min(m-1,i-1)-max(0,i-n)+1);
		s=s*ksm(nv,ct)%mo;		
	}
	return s;
}
int main()
{
	int t;
	cin>>t;
	int R=33333332;
	js[0]=1;
	fo(i,1,R) js[i]=js[i-1]*(LL)i%mo;
	while(t--)
	{
		cin>>n>>m;
		memset(c,0,sizeof(c));
		fo(i,0,n-1) c[i%3][0]++;		
		fo(i,n,n+m-1) c[i%3][1]++;
		r=max(max(c[0][0]*c[0][1],c[1][0]*c[1][1]),c[2][0]*c[2][1]);
		LL v=1;
		int e=c[0][0]*c[0][1]+c[1][0]*c[1][1]+c[2][0]*c[2][1];
		printf("%lld\n",calc(0)*calc(1)%mo*calc(2)%mo*js[e]%mo);
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章