A. A Healthy Breakfast
模拟
代码实现
s = input()
if s.index('R') < s.index('M'):
print('Yes')
else:
print('No')
B. Vertical Reading
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
string s, t;
cin >> s >> t;
for (int w = 1; w < s.size(); ++w) {
rep(c, w) {
string nt;
for (int i = c; i < s.size(); i += w) {
nt += s[i];
}
if (nt == t) {
puts("Yes");
return 0;
}
}
}
puts("No");
return 0;
}
C. Move It
只需考虑物品个数 \(>1\) 的箱子,保留其中最重的物品,将剩下的物品移除即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n), w(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> w[i];
vector<vector<int>> box(n);
rep(i, n) box[a[i]-1].push_back(w[i]);
int ans = reduce(w.begin(), w.end());
rep(i, n) {
if (box[i].size() == 0) continue;
ans -= ranges::max(box[i]);
}
cout << ans << '\n';
return 0;
}
D. Ghost Ants
注意到坐标 \(x\) 且面朝左的蚂蚁,与这个蚂蚁擦肩而过的是坐标范围为 \(x-2t \sim x-1\) 之间的面朝右的蚂蚁。可以用二分来找出有多少只蚂蚁和它擦肩而过。那么我们只需枚举面朝左的蚂蚁即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n; ll t;
cin >> n >> t;
string s;
cin >> s;
vector<ll> neg, pos;
rep(i, n) {
int x;
cin >> x;
if (s[i] == '0') neg.push_back(x);
else pos.push_back(x);
}
sort(neg.begin(), neg.end());
sort(pos.begin(), pos.end());
auto left_count = [&](ll r) {
return lower_bound(pos.begin(), pos.end(), r) - pos.begin();
};
ll ans = 0;
for (ll x : neg) {
ll l = x-t*2, r = x;
ans += left_count(r) - left_count(l);
}
cout << ans << '\n';
return 0;
}
E. Random Swaps of Balls
记 dp[i][j]
表示执行 \(i\) 次操作最终黑球落在第 \(j\) 个位置上的概率
注意到,这里 \(j = 2, 3, \cdots, n\) 时的概率一定是相同的,因为黑球是等概率地和第 \(j\) 个位置上的球进行交换的。那么我们只需考虑 \(j = 1\) 时的概率即可
考虑重新定义dp
记 dp[i]
表示执行 \(i\) 次操作最终黑球落在第 \(1\) 个位置上的概率
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using mint = modint998244353;
int main() {
int n, k;
cin >> n >> k;
mint p = mint(2)/n/n;
mint x = 1;
rep(ki, k) {
x = x*(1-p*(n-1)) + (1-x)*p;
}
mint ans = x + (1-x)*(mint(2+n)/2);
cout << ans.val() << '\n';
return 0;
}
F. InterSections
区间 \([l, r]\) 和区间 \([l_b, r_b]\) 相交当且仅当 \(l_b < l < r_b < r\) 或 \(l < l_b < r < r_b\)
\(l_b < l < r_b < r \Leftrightarrow l_b < l < r_b\) 且 \(r_b < r\)
\(l < l_b < r < r_b \Leftrightarrow l < l_b\) 且 \(l_b < r < r_b\)
考虑将它们放在平面坐标上考虑,令 \(x = l\),\(y = r\),于是就得到了两个不相交的矩形,我们只需统计最多有多少个矩形覆盖点 \((l, r)\) 的即可,可以用扫描线辅助线段树来加速
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
// Coodinate Compression
template<typename T=int>
struct CC {
bool initialized;
vector<T> xs;
CC(): initialized(false) {}
void add(T x) { xs.push_back(x);}
void init() {
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end());
initialized = true;
}
int operator()(T x) {
if (!initialized) init();
return upper_bound(xs.begin(), xs.end(), x) - xs.begin() - 1;
}
T operator[](int i) {
if (!initialized) init();
return xs[i];
}
int size() {
if (!initialized) init();
return xs.size();
}
};
struct S {
int val, y;
S(int val=0, int y=-1): val(val), y(y) {}
};
S op(S a, S b) {
if (a.val > b.val) return a;
if (a.val < b.val) return b;
if (a.y < b.y) return a;
return b;
}
S e() { return S(); }
S mapping(int f, S x) {
x.val += f;
return x;
}
int composition(int g, int f) { return f+g; }
int id() { return 0; }
struct Rect {
int lx, rx, ly, ry;
Rect(int lx=0, int rx=0, int ly=0, int ry=0): lx(lx), rx(rx), ly(ly), ry(ry) {}
};
struct Event {
int l, r, val;
Event(int l=0, int r=0, int val=0): l(l), r(r), val(val) {}
};
int main() {
int n;
cin >> n;
vector<Rect> rects;
const int M = 1e9;
rep(i, n) {
int l, r;
cin >> l >> r;
rects.emplace_back(0, l, l+1, r);
rects.emplace_back(l+1, r, r+1, M+1);
}
CC xs, ys;
for (auto [lx, rx, ly, ry] : rects) {
xs.add(lx); xs.add(rx);
ys.add(ly); ys.add(ry);
}
vector<vector<Event>> events(xs.size());
for (auto&& [lx, rx, ly, ry] : rects) {
lx = xs(lx); rx = xs(rx);
ly = ys(ly); ry = ys(ry);
events[lx].emplace_back(ly, ry, 1);
events[rx].emplace_back(ly, ry, -1);
}
lazy_segtree<S, op, e, int, mapping, composition, id> t(ys.size());
rep(i, ys.size()) t.set(i, S(0, i));
int ans = 0, ansl = 0, ansr = 1;
rep(xi, xs.size()) {
for (auto [l, r, val] : events[xi]) {
t.apply(l, r, val);
}
S s = t.all_prod();
if (ans < s.val) {
ans = s.val;
ansl = xs[xi];
ansr = ys[s.y];
}
}
cout << ansl << ' ' << ansr << '\n';
return 0;
}
G. Suitable Edit for LIS
记 dp[i][x][j]
表示到第 \(i\) 个数为止已经改变了 \(j\)(取值为0/1) 次末尾的值且末尾的值以 \(x\) 结尾的 LIS 的长度
然后用线段树优化一下即可
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
// Coodinate Compression
template<typename T=int>
struct CC {
bool initialized;
vector<T> xs;
CC(): initialized(false) {}
void add(T x) { xs.push_back(x);}
void init() {
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end());
initialized = true;
}
int operator()(T x) {
if (!initialized) init();
return upper_bound(xs.begin(), xs.end(), x) - xs.begin() - 1;
}
T operator[](int i) {
if (!initialized) init();
return xs[i];
}
int size() {
if (!initialized) init();
return xs.size();
}
};
int op(int a, int b) { return max(a, b); }
int e() { return 0; }
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
CC cc;
rep(i, n) cc.add(a[i]);
rep(i, n) cc.add(a[i]+1);
cc.add(0);
int m = cc.size();
segtree<int, op, e> t0(m), t1(m);
auto upd = [&](auto& t, int i, int x) {
t.set(i, max(x, t.get(i)));
};
int cj = 0, cx = 1;
rep(i, n) {
int j = cc(a[i]);
int now0 = t0.prod(0, j);
int now1 = t1.prod(0, j);
upd(t0, j, now0+1);
upd(t1, j, now1+1);
upd(t1, cj, cx);
cj = j+1; cx = now0+2;
}
int ans = t1.all_prod();
cout << ans << '\n';
return 0;
}