Codeforces Round #442 (Div. 2)

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 ,则要求就是:

mrml1(erel1)=k(mrer)(ml1el1)=k

也就是问 pi=miei 差恰好为 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值