Educational Codeforces Round 175 (Rated for Div. 2)
A. FizzBuzz Remixed
题意:求\([0, n]\)里有多少数模3和模5的值一样。
我是打表发现每15个数的开头3个数满足要求。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::cout << n / 15 * 3 + std::min(n % 15 + 1, 3) << "\n";
}
B. Robot Program
题意:坐标轴上从起点按照给定指令序列按顺序执行,如果到了0这个位置就从头开始执行指令,问\(k\)次指令后经过了几次0。
\(k\)很大,但如果我们经过0,就会陷入一个循环。于是先求几步可以到0,然后在计算从0到0这个循环需要几步,就可以之间计算还有多少个循环可以执行。
点击查看代码
void solve() {
i64 n, x, k;
std::cin >> n >> x >> k;
std::string s;
std::cin >> s;
i64 ans = 0;
for (int i = 0; x != 0 && i < n && k; ++ i) {
-- k;
if (s[i] == 'L') {
-- x;
} else {
++ x;
}
}
if (x == 0) {
++ ans;
for (int i = 0; i < n; ++ i) {
if (s[i] == 'L') {
-- x;
} else {
++ x;
}
if (x == 0) {
ans += k / (i + 1);
break;
}
}
}
std::cout << ans << "\n";
}
C. Limited Repainting
题意:一个序列初始都是R,每个位置有一个价值。你可以选择\(k\)个区间把位置都变成B,有一个最终序列\(s\),如果最后你的序列和\(s\)有不一样的地方,代价就是不一样的地方的价值的最大值。求最小代价。
二分答案,如果\(s[i] = R\) && \(a[i] > mid\)则这个位置绝对不能选。否则其它可以选的位置就是一段段区间,如果一个区间有一个\(s[i] = B\) && \(a[i] > mid\)的地方就必须选。看必须选的区间数是不是小于等于\(k\)。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::string s;
std::cin >> s;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
auto check = [&](int x) -> int {
std::vector<int> b(n);
for (int i = 0; i < n; ++ i) {
if (s[i] == 'B') {
b[i] = 1;
} else if (s[i] == 'R' && a[i] <= x) {
b[i] = 1;
}
}
int cnt = 0;
for (int i = 0; i < n; ++ i) {
if (b[i] == 1) {
int j = i;
bool flag = s[i] == 'B' && a[i] > x;
while (j + 1 < n && b[j + 1] == 1) {
++ j;
flag |= s[j] == 'B' && a[j] > x;
}
if (flag) {
++ cnt;
}
i = j;
}
}
return cnt <= k;
};
int l = 0, r = 1e9;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
std::cout << l << "\n";
}
D. Tree Jumps
题意:给你一棵树,根可以到其中任意一个儿子,但从深度为2的点开始,每个点只能去深度比它大一的点,且这个点不是它到儿子。求从根开始的不同路径树。
类似\(DAG\)图路径计数,我们只能一层一层走,那么我们就一层一层算,当前点可以从上一层除了父亲过了,那么记录到达每个点的路径数\(f\),以及每一层的点的路径数总和\(sum\),则以该点为终点的路径数为\(sum - f_{p_i}\)。其中\(p_i\)是\(i\)的父亲。
代码省略了取模类
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<std::vector<int>> adj(n);
std::vector<int> p(n);
for (int i = 1; i < n; ++ i) {
std::cin >> p[i];
-- p[i];
adj[p[i]].push_back(i);
}
std::vector<int> d(n);
std::vector<std::vector<int>> g(n);
auto dfs = [&](auto self, int u) -> void {
g[d[u]].push_back(u);
for (auto & v : adj[u]) {
d[v] = d[u] + 1;
self(self, v);
}
};
dfs(dfs, 0);
std::vector<Z> f(n);
Z sum = 0;
for (auto & u : adj[0]) {
f[u] = 1;
sum += 1;
}
Z ans = sum + 1;
for (int i = 2; i < n; ++ i) {
Z t = 0;
for (auto & u : g[i]) {
f[u] = sum - f[p[u]];
t += f[u];
}
sum = t;
ans += t;
}
std::cout << ans << "\n";
}
E. Game with Binary String
题意:\(Alice\)和\(Bob\)在\(01\)串上做游戏,\(Alice\)先手。\(Alice\)只能拿"\(00\)",\(Bob\)只能拿其它的。给你一个\(01\)串,求有多少子串使得\(Alice\)能赢。
首先\(Bob\)肯定优先拿"\(01\)"和"\(10\)",因为这样可以最大程度断\(Alice\)的操作。那么每次\(Alice\)拿两个\(0\),\(Bob\)拿一个\(0\)一个\(1\),一轮就减少三个\(0\)一个\(1\),那么如果\(Alice\)想赢,\(0\)的数量至少得是\(1\)的数量的三倍多两个。假设\(cnt_0 \geq 3 \times cnt_1 + 2\),那么只要满足这个条件就是可以的,最极端的情况是"\(1010101000...\)"这种,这样可以让\(Alice\)操作数最小,但我们本来就让给了\(cnt_1\)个\(0\)给\(Bob\),所以这个情况也是赢。但还有一个情况,就是\(cnt_0 = 3 \times cnt_1 - 1\),这种情况就是"\(010\)"这种,操作完后\(Bob\)只剩一个\(1\),无法操作,也是\(Alice\)赢。
于是我们记录每个前缀的值\(sum_i\),等于\(0\)的地方就\(+1\),否则\(-3\),这样就表示了\(cnt_0 - 3\times cnt_1\),对于每个位置,相当于找\(sum_i - sum_j \geq 2\)以及\(sum_i - sum_j = -1\)的地方。用树状数组维护维护值域即可。由于有负数,需要整体右移。
点击查看代码
template <class T>
struct Fenwick {
int n;
std::vector<T> tr;
Fenwick(int _n) {
init(_n);
}
void init(int _n) {
n = _n;
tr.assign(_n + 1, T{});
}
void add(int x, const T &v) {
for (int i = x; i <= n; i += i & -i) {
tr[i] = tr[i] + v;
}
}
T query(int x) {
T res{};
for (int i = x; i; i -= i & -i) {
res = res + tr[i];
}
return res;
}
T sum(int l, int r) {
return query(r) - query(l - 1);
}
};
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
const int D = 3 * n + 10;
std::vector<int> sum(n + 1);
sum[0] = D;
for (int i = 0; i < n; ++ i) {
sum[i + 1] = sum[i] + (s[i] == '0' ? 1 : -3);
}
Fenwick<int> tr(D * 2);
tr.add(sum[0], 1);
i64 ans = 0;
for (int i = 1; i <= n; ++ i) {
ans += tr.sum(sum[i] + 1, sum[i] + 1);
ans += tr.query(sum[i] - 2);
tr.add(sum[i], 1);
}
std::cout << ans << "\n";
}

浙公网安备 33010602011771号