Codeforces Round #442 (Div. 2)
好久以来最手速的一场…
C. Slava and tanks
考虑将格子黑白染色,先炸黑色,再炸白色,再炸黑色即可。
#include <bits/stdc++.h>
using namespace std;
int n;
int main()
{
cin >> n;
if (n == 1) { cout << 2 << "\n" << 1 << " " << 1 << endl; return 0; }
cout << (n/2)*2+(n-n/2) << endl;
for (int i = 2; i <= n; i += 2)
cout << i << " ";
for (int i = 1; i <= n; i += 2)
cout << i << " ";
for (int i = 2; i <= n; i += 2)
cout << i << " ";
cout << endl;
return 0;
}
D. Olya and Energy Drinks
考虑bfs的瓶颈,由于每个元素只会被访问一次,用 4n 个并查集维护一下沿一条线未被访问的下一个元素即可。复杂度 O(n2α(n)) 。
一个会TLE的方案:由于下一个节点一定是一段区间,考虑线段树优化。如果用堆优化dij则复杂度为 O(n2log2n) 。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int g[MAXN][MAXN];
char str[MAXN];
int L[MAXN][MAXN], R[MAXN][MAXN], U[MAXN][MAXN], D[MAXN][MAXN];
inline int findf(int fa[], int nd)
{ return fa[nd]!=nd?fa[nd]=findf(fa, fa[nd]):nd; }
int n, m, k;
bool vis[MAXN][MAXN];
int dis[MAXN][MAXN];
queue<pair<int,int> > que;
void place(int x, int y)
{
vis[x][y] = 1;
if (g[x][y-1]==0) L[x][y] = y-1; else L[x][y] = 0;
if (g[x][y+1]==0) R[x][y] = y+1; else R[x][y] = m+1;
if (g[x-1][y]==0) U[y][x] = x-1; else U[y][x] = 0;
if (g[x+1][y]==0) D[y][x] = x+1; else D[y][x] = n+1;
}
int bfs(int Sx, int Sy, int Tx, int Ty)
{
place(Sx, Sy), dis[Sx][Sy] = 0, que.push(make_pair(Sx, Sy));
while (!que.empty()) {
int x = que.front().first, y = que.front().second; que.pop();
// cerr << x << " " << y << " " << dis[x][y] << endl;
if (x == Tx && y == Ty) return dis[x][y];
for (int t = findf(L[x], y); t >= 1 && t >= y-k; t = findf(L[x], t))
place(x, t), dis[x][t] = dis[x][y]+1, que.push(make_pair(x, t));
for (int t = findf(R[x], y); t <= m && t <= y+k; t = findf(R[x], t))
place(x, t), dis[x][t] = dis[x][y]+1, que.push(make_pair(x, t));
for (int t = findf(U[y], x); t >= 1 && t >= x-k; t = findf(U[y], t))
place(t, y), dis[t][y] = dis[x][y]+1, que.push(make_pair(t, y));
for (int t = findf(D[y], x); t <= n && t <= x+k; t = findf(D[y], t))
place(t, y), dis[t][y] = dis[x][y]+1, que.push(make_pair(t, y));
}
return -1;
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++) {
scanf("%s", str+1);
for (int j = 1; j <= m; j++)
g[i][j] = str[j]=='#'?1:0;
}
for (int i = 1; i <= n+1; i++)
for (int j = 1; j <= m+1; j++)
L[i][j] = R[i][j] = j, U[j][i] = D[j][i] = i;
int x, y, z, w;
cin >> x >> y >> z >> w;
cout << bfs(x, y, z, w) << endl;
return 0;
}
E. Danil and a Part-time Job
什么水题…
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int dat[MAXN*4], tag[MAXN*4], l[MAXN*4], r[MAXN*4], lc[MAXN*4], rc[MAXN*4], top = 0, root = 0;
void build(int &nd, int opl, int opr)
{
nd = ++top, l[nd] = opl, r[nd] = opr, tag[nd] = dat[nd] = 0;
if (opl < opr)
build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
}
void pdw(int nd)
{
if (!tag[nd]) return;
dat[nd] = r[nd]-l[nd]+1-dat[nd];
if (lc[nd]) tag[lc[nd]] ^= 1, tag[rc[nd]] ^= 1;
tag[nd] = 0;
}
void modify(int nd, int opl, int opr)
{
if (l[nd] == opl && r[nd] == opr) tag[nd] ^= 1;
else {
int mid = (l[nd]+r[nd])>>1;
if (opr <= mid) modify(lc[nd], opl, opr);
else if (opl > mid) modify(rc[nd], opl, opr);
else modify(lc[nd], opl, mid), modify(rc[nd], mid+1, opr);
pdw(nd), pdw(lc[nd]), pdw(rc[nd]), dat[nd] = dat[lc[nd]]+dat[rc[nd]];
}
}
int query(int nd, int opl, int opr)
{
pdw(nd);
if (l[nd] == opl && r[nd] == opr) return dat[nd];
else {
int mid = (l[nd]+r[nd])>>1;
if (opr <= mid) return query(lc[nd], opl, opr);
else if (opl > mid) return query(rc[nd], opl, opr);
else return query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr);
}
}
struct node {
int to, next;
} edge[MAXN];
int head[MAXN], tot = 0;
inline void push(int i, int j)
{ edge[++tot] = (node){j, head[i]}, head[i] = tot; }
int dfn[MAXN], out[MAXN], dfn_top = 0;
int a[MAXN];
void dfs(int nd)
{
dfn[nd] = ++dfn_top;
if (a[nd]) modify(root, dfn[nd], dfn[nd]);
for (int j = head[nd]; j; j = edge[j].next) {
int to = edge[j].to;
dfs(to);
}
out[nd] = dfn_top;
}
int n, t, p, q;
char str[10];
int main()
{
scanf("%d", &n);
for (int i = 2; i <= n; i++) scanf("%d", &p), push(p, i);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(root, 1, n);
dfs(1);
scanf("%d", &q);
for (int i = 1; i <= q; i++) {
scanf("%s %d", str, &t);
if (str[0] == 'p') modify(root, dfn[t], out[t]);
else printf("%d\n", query(root, dfn[t], out[t]));
}
return 0;
}
F. Ann and Books
考虑限制。设数学题的前缀和为 mi ,经济为 ei ,则要求就是:
mr−ml−1−(er−el−1)=k⟺(mr−er)−(ml−1−el−1)=k
也就是问 pi=mi−ei 差恰好为 k <script type="math/tex" id="MathJax-Element-8">k</script>的对数。这容易用莫队处理。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n, t[MAXN], a[MAXN];
long long e[MAXN], m[MAXN], p[MAXN];
unordered_map<long long, int> st;
int k;
int top = 0;
int q;
int block_size;
struct query {
int l, r, id;
friend bool operator < (const query &a, const query &b)
{ return a.l/block_size == b.l/block_size ? a.r < b.r : a.l < b.l; }
} pt[MAXN];
int T[MAXN];
long long ans[MAXN];
int tarR[MAXN], tarL[MAXN], pos[MAXN];
int main()
{
scanf("%d%d", &n, &k);
block_size = sqrt(n)+1;
st[0] = ++top;
for (int i = 1; i <= n; i++) scanf("%d", &t[i]);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
e[i] = e[i-1], m[i] = m[i-1];
if (t[i] == 1) m[i] += a[i];
else e[i] += a[i];
p[i] = m[i]-e[i];
if (!st.count(p[i])) st[p[i]] = ++top;
// p[i] = st[p[i]];
// cerr << p[i] << " ";
}
// cerr << endl;
scanf("%d", &q);
for (int i = 1; i <= q; i++) scanf("%d%d", &pt[i].l, &pt[i].r), pt[i].id = i;
sort(pt+1, pt+q+1);
// cerr << "HA" << endl;
for (int i = 0; i <= n; i++) {
if (st.count(p[i]+k)) tarR[i] = st[p[i]+k];
if (st.count(p[i]-k)) tarL[i] = st[p[i]-k];
p[i] = st[p[i]];
}
// cerr << "HA" << endl;
int L = 1, R = 0;
long long Ans = 0;
int pos;
for (int i = 1; i <= q; i++) {
while (L > pt[i].l) {
T[p[--L]]++;
if (tarR[L-1])
Ans += T[tarR[L-1]];
}
while (R < pt[i].r) {
if (tarL[R+1])
Ans += T[tarL[R+1]]+(p[L-1] == tarL[R+1]);
T[p[++R]]++;
}
while (L < pt[i].l) {
if (tarR[L-1])
Ans -= T[tarR[L-1]];
T[p[L++]]--;
}
while (R > pt[i].r) {
T[p[R]]--;
if (tarL[R])
Ans -= T[tarL[R]]+(p[L-1] == tarL[R]);
R--;
}
ans[pt[i].id] = Ans;
}
for (int i = 1; i <= q; i++)
printf("%lld\n", ans[i]);
return 0;
}