The 2019 Asia Nanchang First Round Online Programming Contest 部分题解

开局有人过C,我就去钻研C了,想了那么久,卧槽,这题好像有点难度,一看榜好多人切了这题,我就知道,今天想拿到名额,这题不得不切,于是我放弃所有题硬肝这题,期间队友让我想H,我把我的想法给他们后继续肝C,5个小时想了好几个线段树维护dp的假算法,导致最终大崩盘,只有两个题。赛后我用我提供给他们的想法一发切H,I题树套树更是一眼看出思路,15分钟就手写完树套树(然而tle了),E题感觉有点难度,现场我想出来的几率不大,看了中南网友的题解博客都看了好久才懂,最场比赛,就算我开局放弃C,恐怕也只能稳4题(果然如我预料,想拿名额C必切)
C. Hello 2019

cf原题,没啥好说的,链接:Good Bye 2016 E. New Year and Old Subsequence
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10, inf = 1e9;
void up(int &x, int y) {
    x = min(x, y);
}
struct mat {
    int d[5][5];
    mat operator+(const mat& t) const {
        mat tmp;
        for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++) {
            tmp.d[i][j] = inf;
            for (int k = 0; k < 5; k++)
                up(tmp.d[i][j], d[i][k] + t.d[k][j]);
        }
        return tmp;
    }
} cat[maxn * 4];
#define ls o * 2
#define rs o * 2 + 1
#define mid (l + r) / 2
char s[maxn];
void build(int o, int l, int r) {
    if (l == r) {
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
                cat[o].d[i][j] = ((i == j) ? 0 : inf);
        if (s[l] == '2')
            cat[o].d[0][0] = 1, cat[o].d[0][1] = 0;
        else if (s[l] == '0')
            cat[o].d[1][1] = 1, cat[o].d[1][2] = 0;
        else if (s[l] == '1')
            cat[o].d[2][2] = 1, cat[o].d[2][3] = 0;
        else if (s[l] == '9')
            cat[o].d[3][3] = 1, cat[o].d[3][4] = 0;
        else if (s[l] == '8')
            cat[o].d[3][3] = 1, cat[o].d[4][4] = 1;
        return;
    }
    build(ls, l, mid);
    build(rs, mid + 1, r);
    cat[o] = cat[ls] + cat[rs];
}
mat qu(int o, int l, int r, int ql, int qr) {
    if (l >= ql && r <= qr)
        return cat[o];
    if (qr <= mid)
        return qu(ls, l, mid, ql, qr);
    else if (ql > mid)
        return qu(rs, mid + 1, r, ql, qr);
    else return qu(ls, l, mid, ql, qr) + qu(rs, mid + 1, r, ql, qr);
}
int main() {
    int n, q, l, r;
    scanf("%d%d%s", &n, &q, s + 1);
    reverse(s + 1, s + 1 + n);
    build(1, 1, n);
    while (q--) {
        scanf("%d%d", &l, &r);
        l = n - l + 1;
        r = n - r + 1;
        swap(l, r);
        int ccsu_cat = qu(1, 1, n, l, r).d[0][4];
        if (ccsu_cat == inf)
            ccsu_cat = -1;
        printf("%d\n", ccsu_cat);
    }
}

E. Magic Master
学自中南网友:019南昌网络赛 E. Magic Master

#include<bits/stdc++.h>
using namespace std;
int m, n, vis[12];
int gao(int p) {
    int cat = 1, N = n - 1;
    while (p % m && N > m) {
        cat += N / m;
        if (p / m < N / m) {
            p -= p / m;
            p += N % m;
        }
        else
            p -= N / m * m;
        N -= N / m;
    }
    if (p % m == 0)
        return cat + p / m;
    memset(vis, 0, sizeof(vis));
    int x = 1, cnt = 0;
    while (1) {
        if (!vis[x]) {
            if (++cnt == m) {
                cat++;
                if (x == p)
                    return cat;
                vis[x] = 1;
                cnt = 0;
            }
        }
        x = x % N + 1;
    }
}
int main() {
    int T, q, x;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d", &n, &m, &q);
        m++;
        while (q--) {
            scanf("%d", &x);
            printf("%d\n", gao(x - 1));
        }
    }
}

H. The Nth Item

解法:我们把构建的矩阵的1到1e6的次方打表一下,1e6到1e12次方每隔1e6打表,1e12到2e18每隔1e12再打表,然后我们每次求矩阵快速幂复杂度至多2 * 矩阵相乘,举个例子,x^987654321我们拆开成 x^987000000 * x^654321即可
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5, mod = 998244353, T = 1e6;
struct mat {
    int d[2][2];
    mat operator *(const mat& t) const {
        mat tmp;
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                tmp.d[i][j] = (1ll * d[i][0] * t.d[0][j] + 1ll * d[i][1] * t.d[1][j]) % mod;
        return tmp;
    }
};
mat a[maxn], b[maxn], c[maxn * 2], cat;
void init() {
    int N = 1e6;
    cat.d[0][0] = 3, cat.d[0][1] = 2, cat.d[1][0] = 1, cat.d[1][1] = 0;
    a[1] = cat;
    for (int i = 2; i <= N; i++)
        a[i] = a[i - 1] * a[1];
    b[1] = a[N];
    for (int i = 2; i <= N; i++)
        b[i] = b[i - 1] * b[1];
    c[1] = b[N];
    for (int i = 2; i <= N * 2; i++)
        c[i] = c[i - 1] * c[1];
}
ll gao(ll N) {
    if (N == 0)
        return 0;
    if (N == 1)
        return 1;
    N--;
    mat ans;
    int ccsu = 0, ccsu_cat = 0;
    while (N && ccsu < 3) {
        ++ccsu;
        int k = N % T;
        if (ccsu == 3)
            k = N;
        if (k) {
            if (ccsu == 1) {
                if (ccsu_cat)
                    ans = ans * a[k];
                else
                    ans = a[k];
            }
            else if (ccsu == 2) {
                if (ccsu_cat)
                    ans = ans * b[k];
                else
                    ans = b[k];
            }
            else {
                if (ccsu_cat)
                    ans = ans * c[k];
                else
                    ans = c[k];
            }
            ccsu_cat = 1;
        }
        N /= T;
    }
    return ans.d[0][0];
}
int main() {
    init();
    int q;
    ll ans = 0, N;
    scanf("%d%lld", &q, &N);
    for (int i = 1; i <= q; i++) {
        int tmp = gao(N);
        ans ^= tmp;
        N = N ^ (1ll * tmp * tmp);
    }
    printf("%lld\n", ans);
}

I. Yukino With Subinterval

解法:这个题如果不带修改,用前缀和思想直接可持久化线段树即可,带修改的话,我们可以用树状数组套动态开点线段树去实现动态的前缀和,好像没啥好讲的,因为这题思维难度为0…
#include<bits/stdc++.h>
using namespace std;
#define mid (l + r) / 2
#define low(x) x&-x
const int maxn = 2e5 + 2;
int rt[maxn], ls[maxn * 210],  rs[maxn * 210], sum[maxn * 210], cnt;
int a[maxn], n, V[21], tot;
void up(int l, int r, int k, int v) {
    for (int i = 1; i <= tot; i++)
        sum[V[i]] += v;
    if (l == r)
        return;
    if (k <= mid) {
        for (int i = 1; i <= tot; i++) {
            if (!ls[V[i]])
                ls[V[i]] = ++cnt;
            V[i] = ls[V[i]];
        }
        up(l, mid, k, v);
    }
    else {
        for (int i = 1; i <= tot; i++) {
            if (!rs[V[i]])
                rs[V[i]] = ++cnt;
            V[i] = rs[V[i]];
        }
        up(mid + 1, r, k, v);
    }
}
int qu(int l, int r, int ql, int qr) {
    if (l >= ql && r <= qr) {
        int ccsu_cat = 0;
        for (int i = 1; i <= tot; i++)
            ccsu_cat += sum[V[i]];
        return ccsu_cat;
    }
    int ccsu_cat = 0;
    int V2[21];
    if (ql <= mid) {
        for (int i = 1; i <= tot; i++)
            V2[i] = V[i], V[i] = ls[V2[i]];
        ccsu_cat += qu(l, mid, ql, qr);
        for (int i = 1; i <= tot; i++)
            V[i] = V2[i];
    }
    if (qr > mid) {
        for (int i = 1; i <= tot; i++)
            V[i] = rs[V[i]];
        ccsu_cat += qu(mid + 1, r, ql, qr);
    }
    return ccsu_cat;
}
void modify(int x, int k, int v) {
    tot = 0;
    for (; x <= n; x += low(x))
        V[++tot] = rt[x];
    up(1, n, k, v);
}
int query(int x, int ql, int qr) {
    tot = 0;
    for (; x; x -= low(x))
        V[++tot] = rt[x];
    return qu(1, n, ql, qr);
}
int main() {
    int q, opt, l, r, x, y;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
        rt[i] = ++cnt;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        if (a[i] != a[i - 1])
            modify(i, a[i], 1);
    }
    while (q--) {
        scanf("%d%d%d", &opt, &l, &r);
        if (opt == 1) {
            if (a[l] == r)
                continue;
            if (a[l] != a[l - 1])
                modify(l, a[l], -1);
            if (a[l] == a[l + 1])
                modify(l + 1, a[l], 1);
            else if (r == a[l + 1])
                modify(l + 1, a[l + 1], -1);
            a[l] = r;
            if (a[l] != a[l - 1])
                modify(l, a[l], 1);
        }
        else {
            scanf("%d%d", &x, &y);
            int cat = query(r, x, y) - query(l - 1, x, y);
            if (a[l] == a[l - 1] && a[l] >= x && a[l] <= y)
                cat++;
            printf("%d\n", cat);
        }
    }
}

cdq 分治代码:

#include <bits/stdc++.h>
using namespace std;
#define mid (l + r) / 2
#define low(x) x & -x
const int maxn = 2e5 + 10;
struct node
{
    int opt, x, y, v, id;
    bool operator<(const node &t) const
    {
        return x <= t.x;
    }
} cat[maxn * 5], jie[maxn * 5];
int a[maxn], ans[maxn], c[maxn], n;
void up(int x, int v)
{
    for (; x <= n; x += low(x))
        if (!v)
            c[x] = v;
        else
            c[x] += v;
}
int qu(int x)
{
    int res = 0;
    for (; x; x -= low(x))
        res += c[x];
    return res;
}
void cdq(int l, int r)
{
    if (l == r)
        return;
    cdq(l, mid);
    cdq(mid + 1, r);
    int p = l, q = mid + 1, T = l;
    while (p <= mid && q <= r)
    {
        if (jie[p] < jie[q])
        {
            if (jie[p].opt == 0)
                up(jie[p].y, jie[p].v);
            cat[T++] = jie[p++];
        }
        else
        {
            if (jie[q].opt != 0)
                ans[jie[q].id] += jie[q].opt * (qu(jie[q].v) - qu(jie[q].y - 1));
            cat[T++] = jie[q++];
        }
    }
    while (p <= mid)
        cat[T++] = jie[p++];
    while (q <= r)
    {
        if (jie[q].opt != 0)
            ans[jie[q].id] += jie[q].opt * (qu(jie[q].v) - qu(jie[q].y - 1));
        cat[T++] = jie[q++];
    }
    for (int i = l; i <= mid; i++)
        if (jie[i].opt == 0)
            up(jie[i].y, 0);
    for (int i = l; i <= r; i++)
        jie[i] = cat[i];
}
int main()
{
    int q, opt, l, r, x, y, pos, v, tot = 0;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        if (a[i] != a[i - 1])
            jie[++tot] = {0, i, a[i], 1, 0};
    }
    int cnt = 0;
    for (int i = 1; i <= q; i++)
    {
        scanf("%d", &opt);
        if (opt == 1)
        {
            scanf("%d%d", &pos, &v);
            if (a[pos] == v)
                continue;
            if (pos > 1 && a[pos] != a[pos - 1])
                jie[++tot] = {0, pos, a[pos], -1, 0};
            if (pos < n && a[pos] != a[pos + 1])
                jie[++tot] = {0, pos + 1, a[pos + 1], -1, 0};
            a[pos] = v;
            if (pos > 1 && a[pos] != a[pos - 1])
                jie[++tot] = {0, pos, a[pos], 1, 0};
            if (pos < n && a[pos] != a[pos + 1])
                jie[++tot] = {0, pos + 1, a[pos + 1], 1, 0};
        }
        else
        {
            scanf("%d%d%d%d", &l, &r, &x, &y);
            jie[++tot] = {1, r, x, y, ++cnt};
            jie[++tot] = {-1, l, x, y, cnt};
            if (a[l] >= x && a[l] <= y)
                ans[cnt] = 1;
        }
    }
    cdq(1, tot);
    for (int i = 1; i <= cnt; i++)
        printf("%d\n", ans[i]);
}
发布了302 篇原创文章 · 获赞 98 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/100680016