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

可以将原题转化为恰好被 02 整除,恰好被 12 整除,恰好被 22 整除, 时的元素对的和
但这样还是很难做,我们一般会转化成求至少被 02 整除,至少被 12 整除,至少被 22 整除, 时的元素对的和
那么恰好被 k2 整除的元素对的和就等于至少被 k2 整除的元素对的和 至少被 k+12 整除的元素对的和

于是,原题就变成了对于某一位 k,求满足 Ai+Aj0(mod2k) 的元素对的和

做一下式子变形:AjAi(mod2k)

i=1Nj=iN(Ai+Aj)=j=1Ni=1j(Ai+Aj)=j=1N((iAi)+(iAj))

代码实现
#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

莫队
对于 X1 或减 1 时的差值,只需固定 k,计算 |kBi| 的值即可,可以通过离散化+树状数组来加速!总的时间复杂度为 O(nklogn)

貌似这是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;
}