[CF1237F] Balanced Domino Placements

前言

似乎挺套路的?洛谷上竟然是紫题。

题目

洛谷

CF

我得到的略有不同,初始的障碍为基岩,要放置的东西是床,校*老MC了。

讲解

行列分开考虑。

直接分析放床究竟意味着什么,发现行会少掉两个连续的空位,列会少掉任意一个空位,and vice versa.

任意一个空位很好处理,所以我们考虑少掉两个连续的空位怎么搞。

由于行列差不多,所以我们只讲行。

发现初始的基岩将行分隔成了许多个连续的空位,而这些连续又不相邻的空位显然是独立的。

对于一个长度为 \(\rm len\) 的空位,如果要放置 \(k\) 张床,且每张床占用两个空位,那么方案为 \(C_{len-k}^{k}\),对于这些连续空位做个卷积即可求出每张床占用两个空位的方案数了。这个数据规模用 \(\tt NTT\) 意义不大。

\(R_i,C_i\) 分别表示行和列被占用 \(i\) 个两格空位的方案数,令 \(Rtot,Ctot\) 为行列的总空位数,行占用 \(1,2\) 格空位又应该和列占用的 \(2,1\) 格空位对应相同,行的 \(2\) 格空位和列的 \(1\) 格空位任意匹配,行的 \(1\) 格空位和列的 \(2\) 格空位任意匹配,那么答案就呼之欲出了:

\[\sum_{i=0}^{Rtot}\sum_{j=0}^{Rtot-i\times 2} R_i\times C_{Rtot-i\times 2}^j\times C_{j}\times C_{Ctot-j\times 2}^i \times i!\times j! \]

时间复杂度 \(O(n^2)\)

代码

考场代码
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 3605;
const int MOD = 998244353;
int n,m,k;
bool r[MAXN],c[MAXN];
int R[MAXN],C[MAXN],Rtot,Ctot,ans;

LL Read()
{
	LL x = 0,f = 1; char c = getchar();
	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int fac[MAXN],ifac[MAXN],tmp[MAXN];
int qpow(int x,int y)
{
	int ret = 1;
	while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
	return ret;
}
void init(int x)
{
	ifac[0] = fac[0] = 1;
	for(int i = 1;i <= x;++ i) fac[i] = 1ll * fac[i-1] * i % MOD;
	ifac[x] = qpow(fac[x],MOD-2);
	for(int i = x-1;i >= 1;-- i) ifac[i] = ifac[i+1] * (i+1ll) % MOD;
}
LL Co(int x,int y)
{
	if(x < y || y < 0) return 0;
	return 1ll * fac[x] * ifac[y] % MOD * ifac[x-y] % MOD;
}
int S,RS,CS;
void solve(int *a,int len)
{
	for(int i = 0;i <= S+(len>>1);++ i) tmp[i] = 0;
	for(int i = 0;i <= S;++ i)
		for(int j = 0;j <= (len>>1);++ j)
			tmp[i+j] = (tmp[i+j] + Co(len-j,j) * a[i]) % MOD;
	S += len>>1;
	for(int i = 0;i <= S;++ i) a[i] = tmp[i];
} 

int main()
{
//	freopen("bedrock.in","r",stdin);
//	freopen("bedrock.out","w",stdout);
	n = Read(); m = Read(); k = Read();
	init(Max(n,m));
	for(int i = 1;i <= (k<<1);++ i) r[Read()] = 1,c[Read()] = 1;
	for(int i = 1;i <= n;++ i) if(!r[i]) ++Rtot;
	for(int i = 1;i <= m;++ i) if(!c[i]) ++Ctot;
	R[0] = C[0] = 1;
	for(int i = 1,j;i <= n;i = j+1)
	{
		j = i;
		if(r[i]) continue;
		while(j < n && !r[j+1]) ++j;
		solve(R,j-i+1);
	}
	RS = S; S = 0;
	for(int i = 1,j;i <= m;i = j+1)
	{
		j = i;
		if(c[i]) continue;
		while(j < m && !c[j+1]) ++j;
		solve(C,j-i+1);
	}
	CS = S; S = 0;
	for(int i = 0;i <= RS;++ i)//2
		for(int j = Rtot-(i<<1);j >= 0;-- j)//1
		{
			LL Rval = R[i] * Co(Rtot-(i<<1),j) % MOD,Cval = C[j] * Co(Ctot-(j<<1),i) % MOD;
			ans = (ans + Rval * Cval % MOD * fac[i] % MOD * fac[j] % MOD) % MOD;
		}
	Put(ans,'\n');
	return 0;
}
posted @ 2021-10-14 20:57  皮皮刘  阅读(34)  评论(0编辑  收藏  举报