Codeforces Round 921 (Div. 2)
A - We Got Everything Covered!
难度: ⭐
题目大意
给定n和k两个整数, 要求用前k个小写字母组成一个字符串; 该字符串的子串应包含所有由前k个字母组成的长度为n的字符串全排列; 要求输出最短的满足条件的字符串;
解题思路
这题题目挺唬人, 但其实是个水题; 所谓最短, 其实就是把前k个小写字母重复输出n遍就是最短情况了;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
signed main() {
int t;
cin >> t;
while(t--){
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 0; j < m; j++){
cout << (char)('a' + j);
}
}
cout << endl;
}
return 0;
}
B - A Balanced Problemset?
难度: ⭐⭐
题目大意
给定两个整数n和m; 要求把n分为m份, 所得的分数就是这m个数的最大公约数; 请问该分数最大是多少
解题思路
设最大分数是x, 我们可以先分出m份x, 然后把剩下的全放在其中一份上, 并且剩下的部分(n - m * x)也一定是x的倍数(包括0); 这样就把n分为了两部分: m * x和 a * x; 其中a * x就是(n - m * x); 既然要x尽可能大, 也就是让(m + a)尽可能小, 而且(m + a)和x都是n的因数; 所以只要找出第一个大于等于m的因数就可以了;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
signed main() {
int t;
cin >> t;
while(t--){
cin >> n >> m;
int minn = n;
for(int i = 1; i <= n / i; i++){
if(n % i == 0){
if(i >= m) minn = min(minn, i);
if(n / i >= m) minn = min(minn, n / i);
}
}
cout << n / minn << endl;
}
return 0;
}
C - Did We Get Everything Covered?
难度: ⭐⭐⭐
题目大意
和A题相似, 不过这次是给出由前k个字母组成的字符串s, 请问他是否包含所有由前k个字母组成的长度为n的子串; 如果没有则输出任意未包含的字符串;
解题思路
从A题找到的规律就是如果要s满足条件, 那么s就要可以被分成n份, 每份都至少含有前k个字母; 所以我们可以根据这个规律扫一遍字符串s, 看看能不能找出n份; 如果不能, 设我们只找到了m份, 那么就取这m份格子最后一个字母, 再加上当前这份缺的那个字母, 然后用'a'补齐字符串长度, 所得到的就是一个缺失的字符串; 这里读者可以思考一下为什么要取每份的最后一个字母;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
signed main() {
int t;
cin >> t;
while(t--){
int k;
cin >> n >> k >> m;
string s, res = "";
cin >> s;
set<int> st;
int idx = 0;
for(int i = 0; i < s.size(); i++){
st.insert(s[i]);
if(st.size() == k){
res += s[i];
idx++;
st.clear();
}
}
if(idx >= n) cout << "YES" << endl;
else {
for(int i = 0; i < 26; i++){
if(!st.count('a' + i)){
res += ('a' + i);
break;
}
}
while(res.size() < n) res += 'a';
cout << "NO" << endl << res << endl;
}
}
return 0;
}
D - Good Trip
难度: ⭐⭐⭐⭐
题目大意
学校组织k次短途旅行, 每次旅行老师会选择一对学生; 在n个学生中有m对朋友, 每对都有自己的一个初始友谊值fi; 如果老师选中了一对朋友, 那么这对朋友在往后的旅行中友谊值都会+1; 如果不是朋友则仍是0; 请问老师选中的这k对学生的友谊值的和的期望是多少;
解题思路
题意比较难理解; 这题从网上看到一个很妙的题解; 选择一对学生的概率是p = 2 / (n * (n - 1)), 当前所有同学之间友谊值的总和是sum = $\Sigma$ fi; 那么每次选择时, 老师所抽到的学生之间的友谊值期望就是: p * sum; 抽完后友谊值总和增加的概率(抽到朋友时)是: p * m;
所以在k轮抽取中, 每轮答案res都要加上p * sum, 而sum都要更新为sum + 1 * (p * m);
确实很符合逻辑, 但也确实很难想到;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 1e9 + 7;
typedef pair<int, int> PII;
int n, m;
int qmi(int a, int b){
int res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
signed main() {
int t;
cin >> t;
while(t--){
int k;
cin >> n >> m >> k;
int sum = 0, res = 0;
for(int i = 1; i <= m; i++){
int a, b, c;
cin >> a >> b >> c;
sum = (sum + c) % mod;
}
int p = 2 * qmi(n * (n - 1) % mod, mod - 2) % mod;
for(int i = 1; i <= k; i++){
res = (res + p * sum % mod) % mod;
sum = (sum + p * m % mod) % mod;
}
cout << res << endl;
}
return 0;
}