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;
}