Loading

AtCoder Beginner Contest 297




B - chess960

题目大意

给定一串字符串, 里面一定包含2个' B ', 2个' R ', 1个' K ', 问该字符串是否满足以下两个条件, 一是两个'B'所在位置奇偶性不同; 二是'K'的位置在两个'R'之间

解题思路

签到题不多嗦了;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 100+ 10, mod = 998244353;
int n, m;
bool check(int a, int b) {
	bool f1, f2;
	if (a % 2 == 1) f1 = true;
	else f1 = false;
	if (b % 2 == 1) f2 = true;
	else f2 = false;
	if (f1 != f2) return true;
	else return false;
}
signed main(){
	string s;
	cin >> s;
	int x, y, z;
	x = s.find_first_of('B');
	y = s.find_last_of('B');
	if (check(x, y)) {
		x = s.find_first_of('R');
		y = s.find_last_of('R');
		z = s.find('K');
		if (x <= z && z <= y) cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	else cout << "No" << endl;
	return 0;
}




D - Count Subtractions

题目大意

给定两个数a, b; 如果a > b, 则a -= b; 如果b > a, 则b -= a; 问经过多少次操作才能使得a = b;
保证一定有解;

解题思路

直接减肯定会超时, 所以需要用除法来加速;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 100+ 10, mod = 998244353;
int n, m, k;
signed main(){
	cin >> n >> m;
	int a = max(n, m);
	int b = min(n, m);
	while (a != b) {
		int c = a / b;
		if (a % b == 0) c--;
		k += c;
		a -= c * b;
		swap(a, b);
	}
	cout << k << endl;
	return 0;
}




E - Kth Takoyaki Set

题目大意

小莫去买礼物, 现在给定n个礼物以及它们的价格; 并且小莫至少会买一个礼物; 问小莫的多种选择方案中花销第m少的花费是多少; 如果有多种选择方案的花销是相同的, 那么这个花销只能算一次;

解题思路

据说这是一个经典题目. 但是这个题我想的太复杂了, 题解是用set来维护当前最小值; 先把最初的n个价格放进set中, 找到最小值; 这就是最少的花销, 我们把这个数存起来后再把它从set中删去; 然后再遍历最初的n个价格, 让他们都加上当前的最小值, 然后在放进set; 重复上述过程就找到了第2少的花销, 直到找到第m少即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5+ 10, mod = 998244353;
int n, m, k;
int q[N];
set<int> s;
signed main(){
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> q[i];
		s.insert(q[i]);
	}
	for (int i = 1; i < m; i++) {
		int t = *s.begin();
		s.erase(s.begin());
		for (int j = 1; j <= n; j++) {
			s.insert(t + q[j]);
		}
	}
	cout << *s.begin();
	return 0;
}




F - Minimum Bounding Box 2

题目大意

小莫在玩一个撒豆子游戏, 给定一个n* m的大网格, 上面有n*m个格子; 小莫有k个豆子, 随机的撒在上面, 每个豆子都位于一个格子上, 且每个格子最多有一个豆子; 找到最小的可以包含所有豆子的矩形, 所获得的分数就是这个矩形内格子的数量; 现在需要找到所有可能的矩形, 把它们各自的分数加起来再除以可能的矩形数, 答案对mod取模;

解题思路

看题解说是一个容斥原理的好题; 根据题目要求, 满足要求的矩形四条边上都必须有豆子, 这个是不好求的, 所有我们可以倒着求, 求出至少有一条边上没有豆子的情况, 再用总的减去它即可;
我们设上边没有豆子的概率为s1, 右边没有的概率为s2, 下边的概率为s3, 左边为s4; 求出满足这四个概率的其中一个的概率即可, 即s1∪s2∪s3∪s4; 然后我们会想到, 如果右上角的顶点处没有豆子, 那这种情况就被s1和s2算了两次, 所以得减去一次, 这种情况就满足了容斥原理;
只有1条边上没豆子就是( a ): s1 + s2 + s3 + s4; 只有2条边上同时没豆子就是( b ): s1∩s2 + s1∩s3 + s1∩s4 + s2∩s3 + s2∩s4 + s3∩s4; 只有3条边上没豆子就是( c ): s1∩s2∩s3 + s1∩s3∩s4 + s2∩s3∩s4; 4条边上都没豆子就是( d ): s1∩s2∩s3∩s4;
结果就是总的 - a + b - c + d;
设i和j是当前矩形的长和宽, 则: s1 =C( i * ( j - 1 ) , k ), s2 =C( ( i - 1 ) * j , k ), s1∩s2 = C( ( i - 1 ) * ( j - 1 ) , k ), s1∩s3∩s4 = C( ( i - 1 ) * ( j - 2 ) , k), 其他的同理
在求的时候先列举矩形的长和宽i , j , 故该矩形的分数是( i * j ); 网格中这样的矩形有(n - i + 1) * (m - j + 1)个, 这样的矩形内部豆子有多少种排序方式就是用容斥原理来求; 三者相乘就是该大小的矩形所能获得的分数; 求得最终分数后再乘总个数的逆元即可;
注意求组合数时记得判断一下给出的a和b, 如果上标b大于下标a的话无解, 返回0;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e7+ 10, mod = 998244353;
int f[N],nf[N];
set<int> s;
int qmi(int a, int b, int c) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % c;
		a = a * a % c;
		b >>= 1;
	}
	return res;
}
int C(int a, int b, int c) {
	if (a < b) return 0;
	int res = f[a] * nf[b] % c * nf[a - b] % c;
	return res;
}

void ini() {
	f[0] = nf[0] = 1;
	for (int i = 1; i < N; i++) {
		f[i] = f[i - 1] * i % mod;
		nf[i] = nf[i - 1] * qmi(i, mod - 2, mod) % mod;
	}
}
int cal(int n, int m, int k) {
	int x = C(n * m, k, mod);
	int a = (2 * C((n - 1) * m, k, mod) % mod + 2 * C(n * (m - 1), k, mod) % mod)%mod;
	int b = ((C((n - 2) * m, k, mod) + C(n * (m - 2), k, mod)) % mod + 4 * C((n - 1) * (m - 1), k, mod) % mod) % mod;
	int c = (2 * C((n - 1) * (m - 2), k, mod) % mod + 2 * C((n - 2) * (m - 1), k, mod) % mod)%mod;
	int d = C((n - 2) * (m - 2), k, mod);
	int sum = (((x - a + mod) % mod + b - c + mod) % mod + d) % mod;
	return sum;
}
signed main(){
	int n, m, k;
	int res = 0;
	cin >> n >> m >> k;
	if (k == 1) {
		cout << 1;
		return 0;
	}
	ini();
	int fm = C(n * m, k, mod);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (i * j < k) continue;
			int x = i * j % mod;
			int y = (n - i + 1) * (m - j + 1) % mod;
			res = (res + x * y % mod * cal(i, j, k) % mod)%mod;
		}
	}
	res= res * qmi(fm, mod - 2, mod) % mod;
	cout << res;
	return 0;
}
posted @ 2023-06-28 22:11  mostimali  阅读(20)  评论(0编辑  收藏  举报