CF1931G One-Dimensional Puzzle 题解

CF1931G One-Dimensional Puzzle 题解

题意传送门

思路

考虑一下怎么入手,发现一个拼图只能接一些拼图(废话但是有用),所以我们可以简单地画出一个链接关系的图,\(u \to v\) 表示编号为 \(u\) 的拼图后面能够接编号为 \(v\) 的拼图。然后我们发现问题转换为:在这张图上找到一个正好经过每个节点特定次数的路径。

仔细观察这张图,我们可以发现,\(1,2\) 号拼图一定是轮流出现的,也就是说 \(1,2\) 号拼图的数量差一定不能大于 \(1\),不然的话一定会剩下一些 \(1\) 号或者 \(2\) 号拼图。之后可以发现 \(3\) 号只能接在 \(1,2\) 中间,\(4\) 号只能接在 \(2,1\) 中间。

image

之后分类讨论:

  • 如果 \(1\) 的数量和 \(2\) 的数量的差大于 \(1\),则直接输出 \(0\)
  • 如果 \(1,2\) 的数量都为 \(0\) 但是 \(3,4\) 的数量中只有一个或者都为 \(0\),那么就有一种方案。
  • 如果 \(1\) 的数量和 \(2\) 的数量相同,就有两种 \(1,2\) 的排列情况。(假设 \(1,2\) 的数量都有 \(cnt\) 个)
    第一种,\(1\) 先出现:\(1 2 1 2 1 2\ldots\),这样能放 \(3\) 的区间有 \(cnt\) 个,能放 \(4\) 的区间有 \(cnt-1\) 个。
    第一种,\(2\) 先出现:\(2 1 2 1 2 1\ldots\),这样能放 \(3\) 的区间有 \(cnt-1\) 个,能放 \(4\) 的区间有 \(cnt\) 个。
  • 如果 \(1\) 的数量和 \(2\) 的数量相差 \(1\),就只有一种排列情况。(假设 \(1,2\) 的数量中较小的一个数量为 \(cnt\) 个)
    可能是 \(121212\ldots1\) 或者 \(212121\ldots2\),这样能放 \(3\) 的区间个数和能放 \(4\) 的区间个数都是 \(cnt\) 了。

最后我们考虑一个组合数学的问题,就是我们有 \(n\) 个抽屉和 \(m\) 颗球,将球全部放入抽屉中,抽屉可以空着,有多少种放的方法(对应上文放 \(3,4\) 号拼图的情况)。

首先,放入 \(n\) 个抽屉其实就是将原本的 \(m\) 个球分成 \(n\) 个部分,在 \(m\) 个球中插入 \(n-1\) 个隔板,有 \(m-1\) 个可以插板的地方。因为抽屉可以是空着的,所以隔板可以放在一起,为了方便考虑,所以我们可以增加 \(n\) 个球,这样就等于每个抽屉都多一个球,就是原本空抽屉的情况就变成了一个球的情况,最后原问题的答案就是将 \(n-1\) 个板子插入 \(m-1+n\) 个空的方案数,也就是 \(C_{n-1}^{m-1+n}\),需要用快速幂和逆元维护组合数,具体来说,逆元就是一个性质:在 \(\bmod p\) 的意义下(\(p\) 为质数)时,\(a \div x = a \times x^{p-2}\)

喜闻乐见代码环节

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define int long long
const int mod=998244353;
int t1,t2,t3,t4;
int quick_power(int x,int y){
	int ret=1,base=x;
	while(y){
		if(y&1) ret=ret*base%mod;
		base=base*base%mod;
		y>>=1;
	}
	return ret;
}
int C(int n,int m){
	int ret=1;
	for(int i=1;i<=m;i++){
		ret=ret*(n+1-i)%mod;
		ret=ret*quick_power(i,mod-2)%mod;
	}
	return ret;
}
signed main(){
	int t;
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld%lld%lld",&t1,&t2,&t3,&t4);
		if(t1+t2==0&&t3*t4==0){
			printf("1\n");
			continue;
		}
		if(abs(t1-t2)>1||t1+t2==0){
			printf("0\n");
			continue;
		}
		if(t1!=t2){
			int m=min(t1,t2);
			printf("%lld\n",C(t3+m,m)*C(t4+m,m)%mod);	
		}
		if(t1==t2)
			printf("%lld\n",(C(t3+t1,t1)*C(t4+t1-1,t1-1)%mod+C(t3+t1-1,t1-1)*C(t4+t1,t1)%mod)%mod);	
	}
	return 0;
} 
posted @ 2024-03-03 09:04  chenzhiyou2009  阅读(48)  评论(0)    收藏  举报