A. aaaadaa

模拟

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

using namespace std;

int main() {
    int n;
    char c1, c2;
    string s;
    cin >> n >> c1 >> c2 >> s;
    
    rep(i, n) {
        if (s[i] != c1) s[i] = c2;
    }
    
    cout << s << '\n';
    
    return 0;
}

B. ARC Division

模拟

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

using namespace std;

int main() {
    int n, r;
    cin >> n >> r;
    
    rep(i, n) {
        int d, a;
        cin >> d >> a;
        if (d == 1) {
            if (1600 <= r and r <= 2799) r += a;
        }
        else {
            if (1200 <= r and r <= 2399) r += a;
        }
    }
    
    cout << r << '\n';
    
    return 0;
}

C. Perfect Standings

二进制枚举

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

using namespace std;

int main() {
    int n = 5;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    vector<pair<int, string>> ranking;
    rep(s, 1<<n) if (s) {
        string name; int score = 0;
        rep(i, n) {
            if (s>>i&1) {
                score += a[i];
                name += 'A'+i;
            }
        }
        ranking.emplace_back(-score, name);
    }
    
    ranges::sort(ranking);
    
    for (auto [_, name] : ranking) cout << name << '\n';
    
    return 0;
}

D. Repeated Sequence

显然不需要考虑会覆盖多少个完整的序列 \(A\),只需考虑 \(S\) 模掉 \(A\) 的总和的部分即可
对于这部分,如果能找到,那么只会出现在两个序列 \(A\) 拼接在一起的序列中的某个子段中

代码实现
#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 S;
    cin >> n >> S;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    vector<ll> s(n*2+1);
    rep(i, n*2) s[i+1] = s[i]+a[i%n];
    
    ll T = s[n];
    S %= s[n];
    
    set<ll> st;
    rep(i, s.size()) st.insert(s[i]);
    rep(i, s.size()) {
        if (st.count(s[i]-S)) {
            puts("Yes");
            return 0;
        }
    }
    
    puts("No");
    
    return 0;
}

E. Takahashi is Slime 2

贪心,容易想到吸收周围最小的力量最佳,可以开一个小根堆进行扩展

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

using namespace std;
using ll = long long;
using D = tuple<ll, int, int>;

const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};

int main() {
    int h, w, x;
    cin >> h >> w >> x;
    int si, sj;
    cin >> si >> sj; 
    --si; --sj;
    
    vector s(h, vector<ll>(w));
    rep(i, h)rep(j, w) cin >> s[i][j];
    
    ll t = s[si][sj]; s[si][sj] = 0;
    priority_queue<D, vector<D>, greater<D>> q;
    
    vector used(h, vector<bool>(w));
    auto push = [&](int i, int j) {
        rep(v, 4) {
            int ni = i+di[v], nj = j+dj[v];
            if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
            if (used[ni][nj]) continue;
            used[ni][nj] = true;
            q.emplace(s[ni][nj], ni, nj);
        }
    };
    push(si, sj);
    
    while (q.size()) {
        auto [ns, i, j] = q.top(); q.pop();
        if (ns > (t-1)/x) break;
        t += ns;
        push(i, j);
    }
    
    cout << t << '\n';
    
    return 0;
}

F. Double Sum 2

可以将原题转化为恰好被 \(0\)\(2\) 整除,恰好被 \(1\)\(2\) 整除,恰好被 \(2\)\(2\) 整除,\(\cdots\) 时的元素对的和
但这样还是很难做,我们一般会转化成求至少被 \(0\)\(2\) 整除,至少被 \(1\)\(2\) 整除,至少被 \(2\)\(2\) 整除,\(\cdots\) 时的元素对的和
那么恰好被 \(k\)\(2\) 整除的元素对的和就等于至少被 \(k\)\(2\) 整除的元素对的和 \(-\) 至少被 \(k+1\)\(2\) 整除的元素对的和

于是,原题就变成了对于某一位 \(k\),求满足 \(A_i+ A_j \equiv 0 \pmod {2^k}\) 的元素对的和

做一下式子变形:\(A_j \equiv -A_i \pmod {2^k}\)

\( \displaystyle \sum_{i = 1}^N\sum_{j=i}^N (A_i + A_j) = \sum_{j=1}^N\sum_{i=1}^j (A_i + A_j) = \sum_{j=1}^N \left((\sum_i A_i) + (\sum_i A_j)\right) \)

代码实现
#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> a(n);
    rep(i, n) cin >> a[i];
    
    int m = 25;
    vector<ll> d(m);
    rep(k, m) {
        int mod = 1<<k;
        vector<ll> sum(mod), cnt(mod);
        ll now = 0;
        rep(i, n) {
            sum[a[i]%mod] += a[i];
            cnt[a[i]%mod]++;
            int b = (mod-a[i]%mod)%mod;
            now += sum[b];
            now += cnt[b]*a[i];
        }
        d[k] = now;
    }
    
    rep(k, m-1) d[k] -= d[k+1];
    
    ll ans = 0;
    rep(k, m) {
        ans += d[k]>>k;
    }
    
    cout << ans << '\n';
    
    return 0;
}

G. Abs Sum

莫队
对于 \(X\)\(1\) 或减 \(1\) 时的差值,只需固定 \(k\),计算 \(\sum |k-B_i|\) 的值即可,可以通过离散化+树状数组来加速!总的时间复杂度为 \(O(n\sqrt{k}\log n)\)

貌似这是ABC第一次出不是区间的莫队

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

using namespace std;
using ll = long long;

// 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 main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    
    int n;
    cin >> n;
    
    vector<int> a(n), b(n);
    rep(i, n) cin >> a[i];
    rep(i, n) cin >> b[i];
    
    int q;
    cin >> q;
    vector<int> x(q), y(q);
    rep(i, q) cin >> x[i] >> y[i];
    
    vector<int> qis(q);
    rep(i, q) qis[i] = i;
    
    int width = n/(sqrt(q)+1)+1;
    vector<int> block(q);
    rep(i, q) block[i] = y[i]/width;
    ranges::sort(qis, [&](int i, int j) {
        if (block[i] != block[j]) return block[i] < block[j];
        return x[i] < x[j];
    });
    
    CC cc;
    rep(i, n) cc.add(a[i]);
    rep(i, n) cc.add(b[i]);
    int m = cc.size();
    
    ll now = 0;
    fenwick_tree<ll> sa(m), sb(m);
    fenwick_tree<ll> ca(m), cb(m);
    auto addA = [&](int i, int sign=1) { // fix a[i]
        int ai = cc(a[i]);
        now += cb.sum(0, ai)*a[i] * sign;
        now -= sb.sum(0, ai) * sign;
        now -= cb.sum(ai, m)*a[i] * sign;
        now += sb.sum(ai, m) * sign;
        sa.add(ai, a[i]*sign); ca.add(ai, sign);
    };
    auto delA = [&](int i) { addA(i, -1); }; 
    auto addB = [&](int i, int sign=1) { // fix b[i]
        int bi = cc(b[i]);
        now += ca.sum(0, bi)*b[i] * sign;
        now -= sa.sum(0, bi) * sign;
        now -= ca.sum(bi, m)*b[i] * sign;
        now += sa.sum(bi, m) * sign;
        sb.add(bi, b[i]*sign); cb.add(bi, sign);
    };
    auto delB = [&](int i) { addB(i, -1); };
    
    vector<ll> ans(q);
    int nx = 0, ny = 0;
    for (int qi : qis) {
        while (nx < x[qi]) addA(nx), nx++;
        while (nx > x[qi]) nx--, delA(nx);
        while (ny < y[qi]) addB(ny), ny++;
        while (ny > y[qi]) ny--, delB(ny);
        ans[qi] = now;
    }
    
    rep(i, q) cout << ans[i] << '\n'; 
    
    return 0;
}