Educational Codeforces Round 72 Div. 2 解题报告 (CF1217)

C – The Number Of Good Substrings

这道题比较傻逼。

考虑记录上一个最近的\(1\)的位置\(nxt_i\),然后显然的是:如果在\( O(n \log n) \)时间的扫描中扫描到\([l, r]\)大于当前区间,那么就考虑\(l\)左边是否有足够的零来补足长度。然后这道题就可以愉快的 AC 了。

// CF1217C.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 2e5 + 200;

int n, T, nxt[MAX_N];
char opt[MAX_N];

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        int ans = 0;
        scanf("%s", opt);
        n = strlen(opt);
        for (int i = 0; i < n; i++)
            if (opt[i] == '1')
                nxt[i] = i;
            else
                nxt[i] = (i == 0 ? -1 : nxt[i - 1]);
        for (int r = 0; r < n; r++)
        {
            int number = 0;
            for (int l = r; l >= 0 && r - l < 20; l--)
            {
                if (opt[l] == '0')
                    continue;
                number |= 1 << (r - l);
                if (number <= r - (l == 0 ? -1 : nxt[l - 1]))
                    ans++;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

D – Coloring Edges

有一个显然的结论:如果没有环,那么就直接只用一种颜色即可;如果环存在,那么就用两种颜色就行了。一开始把所有的环全部染黑,考虑在环结束的时候进行白色的染色即可,用类似 tarjan 的方法就行了。

// CF1217D.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 5050, MAX_E = 5050;

int head[MAX_N], current, n, m, stat[MAX_N], res[MAX_N];
bool cycle;

struct edge
{
    int to, id, nxt;
} edges[MAX_E];

void dfs(int u)
{
    stat[u] = 1;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (stat[edges[i].to] == 0)
            dfs(edges[i].to), res[edges[i].id] = 1;
        else if (stat[edges[i].to] == 2)
            res[edges[i].id] = 1;
        else
            res[edges[i].id] = 2, cycle = true;
    stat[u] = 2;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for (int i = 1, src, dst; i <= m; i++)
    {
        scanf("%d%d", &src, &dst);
        edges[current].to = dst, edges[current].nxt = head[src];
        edges[current].id = i, head[src] = current++;
    }
    for (int i = 1; i <= n; i++)
        if (stat[i] == 0)
            dfs(i);
    printf("%d\n", cycle ? 2 : 1);
    for (int i = 1; i <= m; i++)
        printf("%d ", res[i]);
    return 0;
}

E – Sum Queries?

这道题大概可以猜到是用线段树进行维护。

我们其实只需要维护「坏的区间」:同位冲突的区间,然后记录每一位最小和次小的值(因为在后续的合并只会用到最小和次小的信息,这样是最优的)。线段树直接合并就行了,比较显然。

// CF1217E.cpp
#include <bits/stdc++.h>
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
#define ll long long

using namespace std;

const ll MAX_N = 2e5 + 200, INF = 0x3f3f3f3f3f3f3f3f;

struct node
{
    ll digits[11][2];
} nodes[MAX_N << 2];

ll buf[11], n, m, ai[MAX_N];

void calc(ll x)
{
    for (int i = 0; i <= 10; i++)
        buf[i] = x % 10, x /= 10;
}

node merge(node ls, node rs)
{
    node res;
    for (int i = 0; i <= 10; i++)
        res.digits[i][0] = res.digits[i][1] = INF;
    for (int i = 0; i <= 10; i++)
    {
        res.digits[i][0] = min(ls.digits[i][0], rs.digits[i][0]);
        res.digits[i][1] = max(ls.digits[i][0], rs.digits[i][0]);
        res.digits[i][1] = min(res.digits[i][1], ls.digits[i][1]);
        res.digits[i][1] = min(res.digits[i][1], rs.digits[i][1]);
    }
    return res;
}

void build(int l, int r, int p)
{
    if (l == r)
    {
        calc(ai[l]);
        for (int i = 0; i <= 10; i++)
        {
            if (buf[i])
                nodes[p].digits[i][0] = ai[l];
            else
                nodes[p].digits[i][0] = INF;
            nodes[p].digits[i][1] = INF;
        }
        return;
    }
    build(l, mid, lson), build(mid + 1, r, rson);
    nodes[p] = merge(nodes[lson], nodes[rson]);
}

void update(ll pos, int l, int r, int p, ll val)
{
    if (l == r)
    {
        calc(val);
        for (int i = 0; i <= 10; i++)
        {
            if (buf[i])
                nodes[p].digits[i][0] = val;
            else
                nodes[p].digits[i][0] = INF;
            nodes[p].digits[i][1] = INF;
        }
        return;
    }
    if (pos <= mid)
        update(pos, l, mid, lson, val);
    else
        update(pos, mid + 1, r, rson, val);
    nodes[p] = merge(nodes[lson], nodes[rson]);
}

node query(ll ql, ll qr, ll l, ll r, ll p)
{
    if (ql <= l && r <= qr)
        return nodes[p];
    node res;
    for (int i = 0; i <= 10; i++)
        res.digits[i][0] = res.digits[i][1] = INF;
    if (ql <= mid)
        res = merge(res, query(ql, qr, l, mid, lson));
    if (mid < qr)
        res = merge(res, query(ql, qr, mid + 1, r, rson));
    return res;
}

int main()
{
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &ai[i]);
    build(1, n, 1);
    while (m--)
    {
        ll opt, l, r;
        scanf("%lld%lld%lld", &opt, &l, &r);
        if (opt == 1)
            update(l, 1, n, 1, r);
        else
        {
            node res = query(l, r, 1, n, 1);
            ll ans = INF;
            for (int i = 0; i <= 10; i++)
                ans = min(ans, res.digits[i][0] + res.digits[i][1]);
            if (ans >= INF)
                puts("-1");
            else
                printf("%lld\n", ans);
        }
    }
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *