A. Jiro

分类讨论

代码实现
#include <bits/stdc++.h>

using namespace std;

int main() {
    char ab, ac, bc;
    cin >> ab >> ac >> bc;
    
    if (ab != ac) puts("A");
    if (ab == bc) puts("B");
    if (bc != ac) puts("C");
    
    return 0;
}

B. Taro

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<bool> taro(n+1);
    rep(i, m) {
        int a; char b;
        cin >> a >> b;
        if (b == 'M') {
            if (taro[a]) puts("No");
            else {
                taro[a] = true;
                puts("Yes");
            }
        }
        else puts("No");
    }
    
    return 0;
}

C. Make Isomorphic

对图 \(H\) 重新编号,暴搜每个点的编号即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

vector<vector<bool>> inputG(int n) {
    vector g(n, vector<bool>(n));
    int m;
    cin >> m;
    rep(i, m) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a][b] = g[b][a] = true;
    }
    return g;
}

int main() {
    int n;
    cin >> n;
    
    auto g = inputG(n);
    auto h = inputG(n);
    vector a(n, vector<int>(n));
    rep(i, n)rep(j, n) if (j>i) {
        cin >> a[i][j];
        a[j][i] = a[i][j];
    }
    
    int ans = 1001001001;
    vector<int> p(n);
    rep(i, n) p[i] = i;
    do {
        int now = 0;
        rep(i, n)rep(j, i) {
            if (h[i][j] != g[p[i]][p[j]]) {
                now += a[i][j];
            } 
        }
        ans = min(ans, now);
    } while (next_permutation(p.begin(), p.end()));
    
    cout << ans << '\n';
    
    return 0;
}

D. 1D Country

注意到这里的坐标是严格递增的,所以直接对坐标离散化,同时对 \(P_i\) 求前缀和即可

代码实现
#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;
    cin >> n;
    
    vector<int> x(n), p(n);
    rep(i, n) cin >> x[i];
    rep(i, n) cin >> p[i];
    
    vector<ll> s(n+1);
    rep(i, n) s[i+1] = s[i]+p[i];
    
    auto f = [&](int r) {
        int pos = upper_bound(x.begin(), x.end(), r) - x.begin();
        return s[pos];
    };
    
    int q;
    cin >> q;
    rep(qi, q) {
        int l, r;
        cin >> l >> r;
        ll ans = f(r) - f(l-1);
        cout << ans << '\n';
    }
    
    return 0;
}

E. I Hate Sigma Problems

原问题可以转成 \(\sum\limits_x \sum\limits_{l \leqslant r} [A_l \cdots A_r \text{中至少有一个}x]\)
其中 \(\sum\limits_{l \leqslant r} [A_l \cdots A_r \text{中至少有一个}x]\) \(=\) 至少有一个 \(x\) 的区间数 \(=\) \(\binom{N+1}{2} -\) 不含有 \(x\) 的区间数
不妨记 \(S_x\) 表示不含有 \(x\) 的区间数,对于这部分就是夹在两个相邻 \(x\) 之间的数能构成的区间个数

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

ll c2(ll n) { return n*(n-1)/2; }

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i], a[i]--;
    
    vector<vector<int>> is(n);
    rep(i, n) is[a[i]].push_back(i);
    
    ll ans = 0;
    rep(x, n) {
        ll sx = 0;
        {
            is[x].push_back(n);
            int pre = -1;
            for (int i : is[x]) {
                sx += c2(i-pre);
                pre = i;
            }
        }
        ans += c2(n+1) - sx;
    }
    
    cout << ans << '\n';
    
    return 0;
}

F. Takahashi in Narrow Road

不妨先将每个坐标 \(X_i\) 变成 \(X_i-i\),这样不会改变任意两个人的相对位置,另外,会让原来的条件就由“不能走到同一点上”变成“可以走到同一点上但不能越过去”。
于是,移动就变成了“把其他碍事的高桥君们也一起移动到同一个坐标上”,只需维护包含 lower_bound、区间set、以及区间求和的延迟线段树即可!

代码实现
#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 ll = long long;

const int INF = 1001001001;
struct S {
    int mx, len;
    ll sum;
    S(int mx=-INF, int len=0, ll sum=0): mx(mx), len(len), sum(sum) {}
};

S op(S a, S b) {
    S res;
    res.mx = max(a.mx, b.mx);
    res.len = a.len + b.len;
    res.sum = a.sum + b.sum;
    return res;
}
S e() { return S(); }

S mapping(int f, S x) {
    if (f == -1) return x;
    x.mx = f;
    x.sum = (ll)f*x.len;
    return x;
}
int composition(int f, int g) {
    if (f == -1) return g;
    return f;
}
int id() { return -1; }

int main() {
    int n;
    cin >> n;
    
    lazy_segtree<S, op, e, int, mapping, composition, id> t(n);
    rep(i, n) {
        int x;
        cin >> x;
        x -= i;
        t.set(i, S(x, 1, x));
    }
    
    ll ans = 0;
    int q;
    cin >> q;
    rep(qi, q) {
        int i, g;
        cin >> i >> g;
        --i; g -= i;
        
        int x = t.get(i).mx;
        int j = 0;
        {
            auto f = [&](S a) {
                return a.mx < g;
            };
            j = t.max_right(0, f);
        }
        if (x < g) {
            int l = i, r = j;
            ans += (ll)g*(r-l) - t.prod(l, r).sum; 
            t.apply(l, r, g);
        }
        else {
            int l = j, r = i+1;
            ans += t.prod(l, r).sum - (ll)g*(r-l); 
            t.apply(l, r, g);
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}

G. Lexicographically Smallest Permutation

从前面开始贪心求最小字典序
考虑对点 \(i\) 向点 \(P_i\) 连一条有向边,这样就得到了若干个置换环
对排列 \((1, 2, \cdots, n)\) 至少经过所有环长的 \(\operatorname{lcm}\) 次操作后将会回到原点
从前面开始考虑,找到每个环里的最小值作为放在第一个的位置,然后剩下的数的位置也就确定了
那么,现在问题就变成了怎么求走到每个环里的最小值的位置所需要的操作次数
记每个环的环长为 \(m_i\),走 \(r_i\) 步可以走到最小值的位置
注意到,操作次数 \(C \bmod m_i = r_i\) 时都可以走到最小值的位置
然后求出同余方程组的最小的解
注意到任意两个模数可能不互质,所以要用扩展中国剩余定理,但又遇到来了高精度问题,可以考虑对每个模数做素因子分解