Codeforces Round 970 (Div. 3)(VP)

A. Sakurako's Exam

总结:一看n <= 20,直接暴力+剪枝即可

inline void solve(){
int a, b;
cin >> a >> b;

vector d;
d.reserve(a + b);
while (a --) {
d.push_back(1);
}
while (b --) {
d.push_back(2);
}

auto dfs = [&](auto&& self, int idx, int sum) ->bool{
if (idx == (int)d.size()) {
return sum == 0;
}
return self(self, idx + 1, sum + d[idx] * 1) || self(self, idx + 1, sum + d[idx] * -1);
};

cout << (dfs(dfs, 0, 0) ? "YES" : "NO") << '\n';
}

B. Square or Not

总结:模拟遍历一遍即可,判断首末行单独判断

inline void solve(){
int n;
cin >> n;

string s;
cin >> s;

if (!mapp[n]) {
cout << "No\n";
return;
}

int length = mapp[n];

bool ok = true;
for (int i = 0; i < n / length; ++i) {
bool is_one = (!i || (i == (n / length) - 1));
auto cur = s.substr(i * length, length);
if (cur[0] != '1' || cur.back() != '1') {
ok = false;
break;
}
auto cnt = count(cur.begin(), cur.end(), '1');
if (is_one) {
if (cnt != length) {
ok = false;
break;
}
}
else {
if (cnt != 2) {
ok = false;
break;
}
}
}

cout << (ok ? "Yes\n" : "No\n");

}

C. Longest Good Array

总结:依然是暴力破解,就是看一个最大终止数值的问题(要求求和<=dif)

inline void solve(){
long long a, b;
cin >> a >> b;

long long dif = (b - a);

long long l = 0, r = dif;

auto valid = [dif](long long x) {
return x * (x + 1) / 2 <= dif;
};
while (l < r) {
long long mid = (l + r + 1) >> 1;
if (valid(mid)) {
l = mid;
}
else {
r = mid - 1;
}
}

cout << (l + 1) << '\n';
}

D. Sakurako's Hobby

总结:求出连通分量即可,因为是permutaton数组,所以保证每个点一定在一个环中(出度入度均为1),具体的tarjan代码参考我的github,有用请点star
https://github.com/yxc-s/programming-template/blob/master/Graph/Tarjan.cpp
或者用dfs(类似于找连通块),并查集也可以解决。。。

inline void solve(){
int n;
cin >> n;

vector<vector> al(n + 1);
for (int i = 1; i <= n; ++i) {
int v;
cin >> v;
al[i].push_back(v);
}

auto circles = Tarjan::getScc(al);

string s;
cin >> s;

vector ans(n + 1);
for (const auto& cur : circles) {
int cnt = 0;
for (const auto& x : cur) {
cnt += s[x - 1] == '0';
}
for (const auto& x : cur) {
ans[x] = cnt;
}
}

for (int i = 1; i <= n; ++i) {
cout << ans[i] << " \n"[i == n];
}

}

E. Alternating String

总结:分奇偶两种情况讨论,奇数的话就依次考虑移除当前数的最小代价(需要维护一个前缀和后缀奇偶各个字符出现的次数)
偶数的话就直接计算

inline void solve(){
int n;
cin >> n;

string s;
cin >> s;

int ans = 0x3f3f3f3f;
if (n & 1) {
vector<vector<vector>> pref(n, vector<vector> (2, vector(26, 0)));
auto suff = pref;
for (int i = 1; i < n; ++i) {
pref[i] = pref[i - 1];
pref[i][(i + 1) & 1][s[i - 1] - 'a'] ++;
}
for (int i = n - 2; i >= 0; --i) {
suff[i] = suff[i + 1];
suff[i][(i + 1) & 1][s[i + 1] - 'a'] ++;
}
for (int i = 0; i < n; ++i) {
int sum_odd = 0;
int sum_even = 0;
int max_odd = 0;
int max_even = 0;
int par = (i + 1) & 1;
for (int j = 0; j < 26; ++j) {
max_odd = max({max_odd, pref[i][1][j] + suff[i][0][j]});
max_even = max({max_even, pref[i][0][j] + suff[i][1][j]});
sum_odd += pref[i][1][j] + suff[i][0][j];
sum_even += pref[i][0][j] + suff[i][1][j];
}
ans = min(ans, sum_odd - max_odd + sum_even - max_even + 1);
}
}
else {
array<int, 26> odd = {};
array<int, 26> even = {};
for (int i = 0; i < n; ++i) {
auto& cur = (i + 1) & 1 ? odd : even;
cur[s[i] - 'a'] ++;
}
ans = accumulate(odd.begin(), odd.end(), 0) - *max_element(odd.begin(), odd.end()) +
accumulate(even.begin(), even.end(), 0) - *max_element(even.begin(), even.end());
}

cout << ans << '\n';
}

posted @ 2024-09-03 10:30  _Yxc  阅读(68)  评论(0)    收藏  举报