T763598 座位优化 (seats) 赛后题解

题目传送门

思路

首先考虑把飞机两侧的座椅(靠窗的)合并,使其成为一个中间的座椅,左右都有过道。

考虑任意两组座椅,如果它们的的大小之差大于 \(2\),则显然使它们更平均更优。

做法

对于第一问,考虑让所有的组都平均,及最大与最小的差不超过 \(1\)。此时一定最优。
计算出最小值以及最大值,算出组内的总和,算出两种的数量即可求出答案。

对于第二问,分类讨论。

  • 如果 \(k=1\),则不存在中间的座位,答案为 (l & 1) ? 2 : 1
  • 如果 \(l\) 为奇数,则考虑枚举,每次将两个 \(l\) 换为 \(l+1\)\(l-1\),显然不便利度不变。此时总共有 \(3\) 种不同大小的组,组合数计算即可。需要注意,\(l=1\) 时需要特殊处理。
  • 如果 \(r\) 为奇数,做法同上。
  • 否则答案为 \(1\)
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int fp(int a, int b)
{
	if(b == 0) return 1;
	int t = fp(a, b >> 1);
	t = t * t % mod;
	if(b & 1) return t * a % mod;
	return t;
}
int fac[200005], ifac[200005];
int C(int n, int m) {return fac[n] * ifac[m] % mod * ifac[n - m] % mod;}
int sum(int l, int r) {return (l + r) * (r - l + 1) / 2;}
int calc(int x) {return (sum(0, (x - 1) / 2) * 2 - ((x & 1) ? x / 2 : 0));}
int calc2(int s1, int s2, int s3)
{
	int n = s1 + s2 + s3;
	return C(n, s1) * C(n - s1, s2) % mod;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	freopen("seats.in", "r", stdin);
	freopen("seats.out", "w", stdout);
	fac[0] = ifac[0] = 1;
	for(int i = 1; i <= 200000; i ++)
	{
		fac[i] = fac[i - 1] * i % mod;
		ifac[i] = fp(fac[i], mod - 2);
	}
	int _;
	cin >> _;
	while(_ --)
	{
		int n, k;
		cin >> n >> k;
		int m = k + 1, l = n / k, r = l + ((n / k * k == n) ? 0 : 1);
		cout << (calc(l) * (k - (n % k)) + calc(r) * (n % k)) << ' ';
		if(k == 1) cout << ((l & 1) ? 2 : 1) << endl;
		else
		{
			if(l & 1)
			{
				if(l == 1)
				{
					int t = calc2(k - (n % k), n % k - 1, 0);
					cout << t << endl;
				}
				else
				{
					int ans = 0;
					for(int i = 0; i <= k - (n % k); i += 2)
					{
						int t = calc2(i / 2, i / 2 + (n % k), k - (n % k) - i);
						ans = (ans + t) % mod;
						if(k - (n % k) - i - 1 >= 0)
						{
							t = calc2(i / 2, i / 2 + (n % k), k - (n % k) - i - 1);
							ans = (ans + t) % mod;
						}
					}
					cout << ans << endl;
				}
			}
			else if(r & 1)
			{
				int ans = 0;
				for(int i = 0; i <= n % k; i += 2)
				{
					int t = calc2(i / 2, i / 2 + k - (n % k), (n % k) - i);
					ans = (ans + t) % mod;
					if((n % k) - i - 1 >= 0)
					{
						t = calc2(i / 2, i / 2 + k - (n % k), (n % k) - i - 1);
						ans = (ans + t) % mod;
					}
				}
				cout << ans << endl;
			}
			else cout << 1 << endl;
		}
	}
	return 0;
}

posted @ 2026-05-23 12:22  yuzihang  阅读(18)  评论(0)    收藏  举报