[ABC339] 赛后总结
[ABC339] 赛后总结
A.TLD
STL1min 秒了。
cout << s.substr(s.rfind('.') + 1);
B.Langton's Takahashi
纯模拟
for(int t = 1; t <= k; t ++) {
if(g[x][y] == 0) {
g[x][y] ^= 1;
d = (d + 1) % 4;
x = dx[d] + x, y = dy[d] + y;
}
else {
g[x][y] ^= 1;
d = (d + 3) % 4;
x = dx[d] + x, y = dy[d] + y;
}
x = (x + n) % n, y = (y + m) % m;
}
C.Perfect Bus
脑筋急转弯
for(int i = 1; i <= n; i ++) {
sum += a[i];
mn = min(mn, sum);
}
cout << sum + (mn < 0 ? -mn : 0) << '\n';
D.Synchronized Players
记忆化寄了,要写 BFS。
queue<qwq> q;
f[a][b][c][d] = 0;
q.push({a, b, c, d});
while(q.size()) {
auto [a, b, c, d] = q.front();
q.pop();
if(st[a][b][c][d]) continue; st[a][b][c][d] = 1;
for(int i = 0; i < 4; i ++) {
int aa = a + dx[i], bb = b + dy[i], cc = c + dx[i], dd = d + dy[i];
if(!check(aa, bb)) aa = a, bb = b;
if(!check(cc, dd)) cc = c, dd = d;
if(aa == a && bb == b && cc == c && dd == d) continue;
f[aa][bb][cc][dd] = min(f[aa][bb][cc][dd], f[a][b][c][d] + 1);
q.push({aa, bb, cc, dd});
}
}
int ans = INF;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++) ans = min(ans, f[i][j][i][j]);
E.Smooth Subsequence
易得
\[f_i = \max_{j < i\wedge a_i - d \le a_j\le a_i + d} f_j + 1
\]
二位偏序,线段树优化即可。
for(int i = 1; i <= n; i ++) {
f[i] = 1;
f[i] = max(f[i], query(1, max(1, a[i] - d), min(M, a[i] + d)) + 1);
update(1, a[i], f[i]);
ans = max(ans, f[i]);
}
F.Product Equality
可以对 \(a_i\) 进行取模,由于出题人卡不到,滚一遍键盘单模数哈希就可以过。
__int128 a[N], mod = 27478509823912369249;
map<__int128, __int128> h;
void work() {
cin >> n;
for(int i = 1; i <= n; i ++) {
string s;
cin >> s;
for(auto c : s) a[i] = a[i] * 10 % mod + (c - '0');
}
for(int i = 1; i <= n; i ++) for(int j = 1; j <= n; j ++) h[a[i] * a[j] % mod] ++;
int ans = 0;
for(int i = 1; i <= n; i ++) ans += h[a[i]];
cout << ans << '\n';
return ;
}
G.Smaller Sum
主席树模板了吧算是,直接存储值域的历史版本就好了。
高贵的 \(O(q\log n + n\log n)\)。
int n, a[N], disc[N], tot, q;
int find(int x) {
return lower_bound(disc + 1, disc + tot + 1, x) - disc;
}
int ls[M], rs[M], idx, root[N], dat[M];
int update(int q, int l, int r, int x, int v) {
int p = ++ idx, mid = l + r >> 1;
ls[p] = ls[q], rs[p] = rs[q], dat[p] = dat[q];
if(l == r) return dat[p] = v, p;
if(x <= mid) ls[p] = update(ls[q], l, mid, x, v);
else rs[p] = update(rs[q], mid + 1, r, x, v);
dat[p] = dat[ls[p]] + dat[rs[p]];
return p;
}
int query(int u, int l, int r, int ql, int qr) {
int mid = l + r >> 1;
if(ql <= l && qr >= r) return dat[u];
int tmp = 0;
if(ql <= mid) tmp = query(ls[u], l, mid, ql, qr);
if(qr > mid) tmp += query(rs[u], mid + 1, r, ql, qr);
return tmp;
}
vector<int> d[N];
void work() {
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i], disc[++ tot] = a[i];
sort(disc + 1, disc + tot + 1);
tot = unique(disc + 1, disc + tot + 1) - disc - 1;
for(int i = 1; i <= n; i ++)
d[find(a[i])].push_back(i);
for(int i = 1; i <= tot; i ++) {
root[i] = root[i - 1];
for(auto x : d[i])
root[i] = update(root[i], 1, n, x, a[x]);
}
cin >> q;
for(int i = 1, lst = 0, l, r, x; i <= q; i ++) {
cin >> l >> r >> x;
l ^= lst, r ^= lst, x ^= lst;
if(x < disc[1]) {
cout << (lst = 0) << '\n';
continue;
}
cout << (lst = query(root[upper_bound(disc + 1, disc + tot + 1, x) - disc - 1], 1, n, l, r)) << '\n';
}
return ;
}
分块也可以,口胡了一下对每块存储值域的前缀和,大概是 \(O(n\sqrt n + q\sqrt n)\) 的。
XY_Eleven大佬写了一个二维树状数组,可以考虑用前缀和转化为 \(1\sim r\) 中 \(1\sim x\) 的数的和,然后用二维数据结构维护即可,时间复杂度是 \(O(n\log^2n + q\log^2n)\) 的。