Codeforces Round 925 (Div. 3)
A. Recovering a Small String
题意:给出一个整数n,为三个26个字母的位置序号的和,输出字典序最小的三个字符的字符串。
思路:直接倒推,顺一遍,后面的字母尽可能大。
AC code:
void solve() {
cin >> n;
string s = "";
if (n > 27) {
n -= 26;
s += 'z';
if (n > 26) {
s += 'z';
n -= 26;
s += char('a' + n - 1);
} else {
s += char('a' + n - 1 - 1);
s += 'a';
}
}else {
s += 'a';
s += 'a';
n -= 2;
s += char('a' + n - 2 + 1);
cout << s << endl;
return;
}
reverse(s.begin(),s.end());
cout << s << endl;
}
B. Make Equal
题意:n杯水,首先一定能平分,前面的水可以往后匀,是否可以通过这种方式使得n杯水平分。
思路:贪心,从前往后捋,高出平均值记录一下,少了就去些。
AC code:
void solve() {
cin >> n;
vector<int> a(n, 0);
int mx = 0;
for (int i = 0; i < n; i ++) cin >> a[i], mx += a[i];
int aver = mx / n, now = 0;
for (int i = 0; i < n; i ++) {
if (a[i] != aver) {
if (a[i] >= aver) {
now += a[i] - aver;
} else {
now -= (aver - a[i]);
if (now < 0) {
cout << "NO" << endl;
return;
}
}
}
}
if (!now) {
cout << "YES" << endl;
return;
}
cout << "NO" << endl;
}
C. Make Equal Again
题意:通过一次操作,操作为选择任意长度区间变为同一个数,将长度为n的数组a的所有元素相同,最小化区间的元素数量。
思路:注意只能操作一次,那么就仨情况了,前半,后半,中间,记录开头连续相同的数量,和结尾连续相同的数量,取最大,若首尾相等则相加,答案则为除了这些相等的头尾的其余元素。
AC code:
void solve() {
cin >> n;
map<int, int> mp;
for (int i = 1; i <= n; i ++) cin >> a[i], mp[a[i]] ++;
int ans = INF;
int cnt = 1, cnt2 = 1;
int l = 1, r = n;
int st = a[1];
for (int i = 2; i <= n; i ++) {
if (a[i] == st) cnt ++;
else break;
}
ans = min(ans, n - cnt);
st = a[n];
for (int i = n - 1; i >= 1; i --) {
if (a[i] == st) cnt2 ++;
else break;
}
ans = min(ans, n - cnt2);
if (a[1] == a[n]) ans = min(ans, n - cnt - cnt2);
ans = max(0LL, ans);
cout << ans << endl;
}
D. Divisible Pairs
题意:找出数组中符合条件的元素对,条件为 a i + a j a_i + a_j ai+aj被x整除, a i − a j a_i - a_j ai−aj被y整除。
思路:根据条件可以得知:
-
a i − a j a_i - a_j ai−aj被y整除即 a i a_i ai % y == 0 && a j a_j aj % y == 0
-
a i + a j a_i + a_j ai+aj被x整除即 ( a i a_i ai%x+ a j a_j aj%x)% x == 0
由以上条件,用map<pair<int, int>, int>来记录每个元素对应xy取模,以第一个条件为基准,定一个元素通过第二个条件找另一个成对元素是否存在,详见代码。
AC code:
void solve() {
cin >> n >> x >> y;
for (int i = 1; i <= n; i ++) cin >> a[i];
sort(a+1, a+n+1);
map<PII, int> mp;
for (int i = 1; i <= n; i ++) {
mp[{a[i] % x, a[i] % y}] ++;
}
int ans = 0;
for (int i = 1; i <= n; i ++) {
int t = (x - (a[i] % x)) % x;
ans += mp[{t, a[i] % y}];
if (a[i] % x == t) ans --;
}
cout << ans / 2 << endl;
}
E. Anna and the Valentine’s Day Gift
题意:A和B对一个n数组中的元素进行轮流操作,A先手
- 当A出手时,选择任意一个元素倒转,若倒转后有前置零则消除
- 当B出手时,选择任意两个不同的元素进行拼接成一个新元素,原序列数量-1
A的获胜条件为最后留下的元素位数小于m,反之B获胜,双方博弈,谁能胜。
思路:
-
重点只在于一个元素是否有可能通过倒置操作减少位数,即末尾是否有连续的0,且对于一个元素倒置最多减少一次位数
-
我们可以计算每个元素初始后置0的数量,然后根据这个进行排序
-
轮到A时则去优先消除后置0多的元素,轮到B则优先可以合并两个元素来保一个后置0
AC code:
int find(int x) {
int cnt = 0;
while (x) {
cnt ++;
x /= 10;
}
return cnt;
}
int find_0(int x) {
int cnt = 0;
while (x % 10 == 0 && x != 0) {
cnt ++;
x /= 10;
}
return cnt;
}
void solve() {
cin >> n >> m;
vector<PII> a(n);
for (int i = 0; i < n; i ++) {
int x; cin >> x;
a[i].second = x;
a[i].first = find_0(x);
}
sort(a.begin(), a.end());
int ans = 0;
for(int i = 0; i < n; i ++) {
int t = a[i].second;
ans += find(t);
if (i % 2 != (n - 1) % 2) continue;
ans -= find_0(t);
}
if (ans > m) cout << "Sasha" << endl;
else cout << "Anna" << endl;
}
F. Chat Screenshots
题意:初始可能会有一个排序序列代表n个用户,用户会发送这个序列,发送的时候把自己调到第一个,即在原序列的基础上,每个用户发送的序列自己都是在第一位的,通过k名用户发送的序列,判断是否可能存在一个初始的序列。
思路:
-
如果可能存在这样的序列,那么不会存在除当前用户之外的序列顺序出现矛盾的情况。
-
这里可以直接存图,判断是否是一个拓扑排序即是否不存在环,存在则有矛盾条件。
-
存图是注意一是不需要存每个用户序列的第一个元素,因为真假存疑,二是除了第一个元素之外序列顺序存,维护前后元素即可。
AC code:
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define db double
#define pb push_back
#define fast() ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;
typedef pair<char, int> PCI;
typedef pair<int, int> PII;
const int N = 2e5+10, M = 2001;
const int INF = 0x3f3f3f3f3f, mod = 998244353;
int T, n, k;
vector<int> g[N];
int d[N];
void solve() {
for (int i = 1; i <= n; i ++) {
g[i].clear(), d[i] = 0;
}
cin >> n >> k;
while (k --) {
vector<int> ca(n);
for (int i = 0; i < n; i ++) cin >> ca[i];
for (int i = 1; i < n - 1; i ++) {
g[ca[i]].pb(ca[i + 1]);
d[ca[i + 1]] ++;
}
}
queue<int> q;
for (int i = 1; i <= n; i ++) {
if (d[i] == 0) q.push(i);
}
int cnt = 0;
while (!q.empty()) {
auto t = q.front();
q.pop();
cnt ++;
for (auto u : g[t]) {
d[u] --;
if (d[u] == 0) q.push(u);
}
}
if (cnt == n) cout << "YES" << endl;
else cout << "NO" << endl;
}
signed main() {
fast();
T = 1;
cin >> T;
while (T --) {
solve();
}
return 0;
}