P6475 [NOI Online #2 入门组] 建设城市
P6475 [NOI Online #2 入门组] 建设城市
题目大意
球球是一位建筑师。一天,他收到市长的任务:建设城市。球球打算建造 \(2n\) 座高楼。为了保证城市美观,球球做出了如下计划:
-
球球喜欢整齐的事物。他希望高楼从左向右排成一行,编号依次为 \(1\sim 2n\)。
-
球球喜欢整数,他要求每座高楼的高度都是正整数。
-
由于材料限制,高楼的高度无法超过 \(m\)。
-
球球喜欢中间高,两边低的造型。他要求前 \(n\) 座高楼的高度不下降,后 \(n\) 座高楼的高度不上升。
-
球球打算选两座编号为 \(x,y\) 的高楼作为这座城市的地标。他认为只有当这两座高楼高度相等时,才会让城市变得美观。
球球把自己的想法告诉了市长。市长希望得知所有建设城市的方案数。两种方案不同,当且仅当某座高楼的高度在两个方案中不同。这个问题可难倒了球球。球球找到了你,希望你能帮他算出答案。由于答案可能很大,你只需要给出答案对 \(998244353\) 取模后的结果。
分析
因为有x,y在这里卡着,因此我们首先肯定是要进行分类讨论。
在此之前,我们首先需要解决一个问题,一个序列有k个数,数字的取值范围为[l,r],则若要使序列单调不降/不升的合法序列个数为多少
结论是,\(C(r-l+1+k,r-l)\)。
这个推导也很容易,可以将问题等价于,k个相同的球放到r-l+1个不同的盒子中的方案数。
接下来,我们来分类讨论。
x<=n&&y>n
我们枚举[x,y]段的取值为i。
- 第一段
[1,x-1],取值范围[1,i] - 第二段
[x+1,n],取值范围[i,m] - 第三段
[n+1,y-1],取值范围[i,m] - 第四段
[y+1,2n],取值范围[1,i]
四段相互独立,利用乘法原理得到。
\[res = C(x-2+i,i-1)*C(m-i+n-x,m-i)*C(m-i+y-(n+1),m-i)*C(i+2*n-y-1,i-1)
\]
x<y<=n||n<x<y
则我们可以将[x,y]看成一个城市。
则\(res=C(m+n-1,m-1)*C(m+n-(y-x)-1,m-1)\)
Ac_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
const int N = 2e5 + 10,mod = 998244353;
template<int T>
struct ModInt {
const static int mod = T;
int x;
ModInt(int x = 0) : x(x % mod) {}
int val() { return x; }
ModInt operator + (const ModInt &a) const { int x0 = x + a.x; if (x0 >= mod) x0 -= mod; if (x0 < 0) x0 += mod; return ModInt(x0); }
ModInt operator - (const ModInt &a) const { int x0 = x - a.x; if (x0 >= mod) x0 -= mod; if (x0 < 0) x0 += mod; return ModInt(x0); }
ModInt operator * (const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
ModInt operator / (const ModInt &a) const { return *this * a.inv(); }
void operator += (const ModInt &a) { x += a.x; if (x >= mod) x -= mod; if (x < 0) x += mod;}
void operator -= (const ModInt &a) { x -= a.x; if (x < 0) x += mod; if (x >= mod) x -= mod;}
void operator *= (const ModInt &a) { x = 1LL * x * a.x % mod; }
void operator /= (const ModInt &a) { *this = *this / a; }
friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x;}
ModInt pow(int n) const {
ModInt res(1), mul(x);
while(n){
if (n & 1) res *= mul;
mul *= mul;
n >>= 1;
}
return res;
}
ModInt inv() const {
int a = x, b = mod, u = 1, v = 0;
while (b) {
int t = a / b;
a -= t * b; swap(a, b);
u -= t * v; swap(u, v);
}
if (u < 0) u += mod;
return u;
}
};
typedef ModInt<mod> mint;
mint fact[N],infact[N];
int m,n,x,y;
void init()
{
fact[0] = infact[0] = 1;
for(int i=1;i<N;i++) fact[i] = fact[i-1]*mint(i);
infact[N-1] = fact[N-1].pow(mod-2);
for(int i=N-2;i;i--) infact[i] = infact[i+1]*mint(i+1);
}
mint C(int a,int b)
{
return fact[a]*infact[a-b]*infact[b];
}
int main()
{
ios;
init();
cin>>m>>n>>x>>y;
mint ans = 0;
if(x<=n&&y>n)
{
for(int i=1;i<=m;i++)
ans += C(x-2+i,i-1)*C(m-i+n-x,m-i)*C(m-i+y-(n+1),m-i)*C(i+2*n-y-1,i-1);
}
else ans = C(m+n-1,m-1)*C(m+n-(y-x)-1,m-1);
cout<<ans<<'\n';
return 0;
}

浙公网安备 33010602011771号