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;
}