P6475 [NOI Online #2 入门组]建设城市 |组合数学

题目描述

球球是一位建筑师。一天,他收到市长的任务:建设城市。球球打算建造 \(2n\) 座高楼。为了保证城市美观,球球做出了如下计划:

球球喜欢整齐的事物。他希望高楼从左向右排成一行,编号依次为 \(1\sim 2n\)。

球球喜欢整数,他要求每座高楼的高度都是正整数。

由于材料限制,高楼的高度无法超过 \(m\)。

球球喜欢中间高,两边低的造型。他要求前 \(n\) 座高楼的高度不下降,后 \(n\) 座高楼的高度不上升。

球球打算选两座编号为 \(x,y\) 的高楼作为这座城市的地标。他认为只有当这两座高楼高度相等时,才会让城市变得美观。

球球把自己的想法告诉了市长。市长希望得知所有建设城市的方案数。两种方案不同,当且仅当某座高楼的高度在两个方案中不同。这个问题可难倒了球球。球球找到了你,希望你能帮他算出答案。由于答案可能很大,你只需要给出答案对 \(998244353\) 取模后的结果。

输入格式

从标准输入读入数据。

仅一行四个整数 \(m,n,x,y\),变量意义见题目描述。

输出格式

输出到标准输出。

仅一行一个整数表示答案。


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int N=2e5+10,M=2e5,mod=998244353;
#define int long long
inline int ksm(int x,int y){
	int ans=1;
	while(y){
		if(y&1)ans=ans*x%mod;
		x=x*x%mod; y>>=1;
	}
	return ans;
}
int n,m,x,y;
int jc[N],inv[N];
inline void pre(){
	jc[0]=1; for(int i=1;i<=M;i++)jc[i]=jc[i-1]*i%mod;
	inv[M]=ksm(jc[M],mod-2);
	for(int i=M-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
inline int C(int x,int y){
	if(y>x)return 0;
	return jc[x]*inv[x-y]%mod*inv[y]%mod;
}
inline int f(int x,int y){
	return C(x+y-1,y-1);
}
signed main(){
	pre(); cin>>m>>n>>x>>y;
	if(y<=n||x>n){
		printf("%lld\n",f(n+x-y,m)*f(n,m)%mod);
	}else{
		int ans=0;
		for(int i=1;i<=m;i++)
		ans=(ans+f(x-1,i)*f(n-x,m-i+1)%mod*f(y-n-1,m-i+1)%mod*f(2*n-y,i)%mod)%mod;
		printf("%lld\n",ans);
	}
}
上一篇:[题解] [Codechef] CNTL


下一篇:BZOJ 4559: [JLoi2016]成绩比较 容斥+组合