2021牛客寒假算法基础集训营3

2021牛客寒假算法基础集训营3

A 模数的世界

a == b == 0直接是0 0 0

其他的就构造 p - 1,

x = a + p(p - a - 1) = (p - 1)(p - a), y = (p - 1)(p - b)

但是可能存在 gcd(p - a, p - b) != 1, 导致构造 p - 1 失败,

那就让 x 一直 += p * (p - 1) 呗, 知道构造出 p - 1

int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll a, b, p; cin >> a >> b >> p;
        if (a == 0 && b == 0) { cout << "0 0 0\n"; continue; }
        a += p * (p - a - 1), b += p * (p - b - 1);
        while (__gcd(a, b) % p != p - 1) a += p * (p - 1);
        cout << p - 1 << ' ' << a << ' ' << b << '\n';
    }
    return 0;
}

B 内卷

贪心就行, 先全部都是最低级E, 不断提高当前分数最低的那个人的分数等级就好了, 就几行, 为啥这么少人过啊

struct { int a[5], deg; } a[N];

int main() {
    IOS; cin >> n >> k; multimap<int, int> st;
    rep (i, 1, n) per (j, 4, 0) cin >> a[i].a[j];
    rep (i ,1, n) st.insert({a[i].a[0], i});
    m = st.rbegin()->first - st.begin()->first;
    while (1) {
        auto it = st.begin(); st.erase(it);
        int x = it->second; ++a[x].deg;
        if (a[x].deg == 4) { if (k) --k; else break; }
        else if (a[x].deg > 4) break;
        st.insert({a[x].a[a[x].deg], x});
        umin(m, st.rbegin()->first - st.begin()->first);
    }
    cout << m;
    return 0;
}

C 重力坠击

数据范围很小, 爆搜

struct node { int x, y, r; }e[N];

void dfs(int now) {
    if(now == k) {
        memset(v, 0, sizeof(v));
        int res = 0;
        rep (i, 1, n) rep (j, 1, k)
            if (sqr(a[j] - e[i].x) + sqr(b[j] - e[i].y)
                <= sqr(r + e[i].r) && v[i] == 0) ++res, v[i] = 1;
        umax(ans, res);
        return;
    }
    rep (i, -7, 7) rep (j, -7, 7) {
        a[now + 1] = i, b[now + 1] = j;
        dfs(now + 1);
    }
}

int main() {
    IOS; cin >> n >> k >> r;
    rep (i, 1, n) cin >> e[i].x >> e[i].y >> e[i].r;
    dfs(0);
    cout << ans << "\n";
    return 0;
}

D Happy New Year!

int main() {
    IOS; cin >> n;
    if (n < 2030) cout << 2030 + (n % 10 - 1);
    else cout << 2102;
    return 0;
}

E 买礼物

最大值线段树, 维护出现上一个a[i]的位置的最大值

struct BIT {
    struct node { int l, r, tag; } tr[N << 2];
    void push_up(int rt) { tr[rt].tag = max(tr[rt << 1].tag, tr[rt << 1 | 1].tag); }
    void build(int rt, int l, int r, int pre[]) {
        tr[rt] = { l, r, 0 };
        if (l == r) { tr[rt].tag = pre[l]; return; };
        int mid = l + r >> 1;
        build(rt << 1, l, mid, pre);
        build(rt << 1 | 1, mid + 1, r, pre);
        push_up(rt);
    }
    void change(int rt, int d, int k) {
        if (tr[rt].l == tr[rt].r && tr[rt].l == d) { tr[rt].tag = k; return; }
        int mid = tr[rt].l + tr[rt].r >> 1;
        if (d <= mid) change(rt << 1, d, k);
        if (d > mid) change(rt << 1 | 1, d, k);
        push_up(rt);
    }
    int ask(int rt, int l, int r) {
        if (tr[rt].l >= l && tr[rt].r <= r) return tr[rt].tag;
        int mid = tr[rt].l + tr[rt].r >> 1, ans = 0;
        if (l <= mid) umax(ans, ask(rt << 1, l, r));
        if (r > mid) umax(ans, ask(rt << 1 | 1, l, r));
        return ans;
    }
} bit;

int n, m, _, k;
int h[M], ne[N], pre[N];

int main() {
    IOS; cin >> n >> k;
    rep(i, 1, n) ne[i] = n + 1;
    rep(i, 1, n) cin >> m, ne[pre[i] = h[m]] = i, h[m] = i;
    bit.build(1, 1, n, pre);
    rep(i, 1, k) {
        int op, l, r; cin >> op >> l;
        if (op == 1) {
            bit.change(1, l, 0);
            if (pre[l]) ne[pre[l]] = ne[l];
            if (ne[l] != n + 1) bit.change(1, ne[l], pre[ne[l]] = pre[l]);
        }
        else {
            cin >> r;
            cout << (l <= bit.ask(1, l, r)) << '\n';
        }
    }
    return 0;
}

F 匹配串

答案明显要么无限要么为0

正反个匹配一次即可, 记录每个串正着和倒着第一次出现'#' 的位置

比如 a#cd#e, a#ef#e, 只要这两个串的正着和倒着到 '#'之前的字串匹配, 那就匹配, 中间的可以用#代替

a#cd#e = aefcde, a#ed#e = aedcde, 当然这只是一种情况, 答案是无限

int main() {
    IOS; cin >> n;
    rep (i, 1, n) cin >> s[i].s, umax(mx, s[i].s.size());
    rep (i, 1, n) {
        rep (j, 0, s[i].s.size() - 1) if (s[i].s[j] == '#') { s[i].p1 = j; break; }
        per (j, s[i].s.size() - 1, 0) if (s[i].s[j] == '#') { s[i].p2 = s[i].s.size() - 1 - j; break; }
    }
    sort(s + 1, s + n + 1, [](node &a, node &b) { return a.p1 < b.p1; });
    int nw = 1; bool f = 0;
    rep (i, 0, mx) {
        while (s[nw].s[i] == '#' && nw < n) ++nw;
        if (nw == n) break;
        char tmp = s[nw].s[i];
        rep (j, nw + 1, n) if (s[j].s[i] != tmp) { f = 1; break; }
    }
    sort(s + 1, s + n + 1, [](node &a, node &b) { return a.p2 < b.p2; });
    nw = 1;
    rep (i, 1, mx - 1) {
        while (s[nw].s[s[nw].s.size() - i] == '#' && nw < n) ++nw;
        if (nw == n) break;
        char tmp = s[nw].s[s[nw].s.size() - i];
        rep (j, nw + 1, n) if (s[j].s[s[j].s.size() - i] != tmp) { f = 1; break; }
    }
    cout << (f ? 0 : -1);
    return 0;
}

G 糖果

权值并查集

int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }

void unit(int x, int y) { x = find(x); y = find(y); if (x != y) f[y] = x, umax(a[x], a[y]), sz[x] += sz[y]; }

int main() {
    IOS; cin >> n >> m;
    rep (i, 1, n) cin >> a[i], f[i] = i, sz[i] = 1;
    rep (i, 1, m) {
        int u, v; cin >> u >> v;
        unit(u, v);
    }
    rep (i, 1, n) if (f[i] == i) ans += sz[i] * a[i];
    cout << ans;
    return 0;
}

H 数字串

int main() {
    IOS; cin >> s; string t = ""; bool f = 0;
    for (int i = 0; s[i]; ++i)
        if (s[i] > 'j' && s[i] != 't') {
            rep (j, 0, i - 1) t += s[j];
            t += (s[i] - 'a' + 1) / 10 + 'a' - 1;
            t += (s[i] - 'a' + 1) % 10 + 'a' - 1;
            for (int j = i + 1; s[j]; ++j) t += s[j];
            f = 1; break;
        } else if (s[i + 1] && max(s[i], s[i + 1]) < 'j' && (s[i] - 'a' + 1) * 10 + (s[i + 1] - 'a' + 1) <= 26) {
            rep (j, 0, i - 1) t += s[i];
            t += (s[i] - 'a' + 1) * 10 + (s[i + 1] - 'a' + 1) + 'a' - 1;
            for (int j = i + 2; s[j]; ++j) t += s[j];
            f = 1; break;
        }
    if (f) cout << t;
    else cout << -1;
    return 0;
}

I 序列的美观度

贪心, 在 (a[i] == a[j]) i~j 之间出现相同的数直接舍弃当前 i 即可

int main() {
    IOS; cin >> n; unordered_set<int> st;
    rep (i, 1, n) {
        cin >> a[i];
        if (st.count(a[i])) ++m, unordered_set<int>().swap(st);
        st.insert(a[i]);
    }
    cout << m;
    return 0;
}

J 加法和乘法

数据才 1e6, 直接模拟游戏比赛即可

int main() {
    IOS; cin>>n; int ji = 0, ou = 0;
    rep (i ,1, n) cin >> m, ji += m % 2; ou = n - ji;
    while(ou + ji > 1) {
        if (ou >= 2) --ou;
        else if (ou >= 1 && ji >= 1) --ou;
        else if (ji >= 2) --ji;
        if (ji >= 2) ji -= 2, ++ou;
        else if (ji >= 1 && ou >= 1) --ji;
        else if(ou >= 2) --ou;
    }
    if (ou) cout << "NiuMei";
    else cout << "NiuNiu";
    return 0;
}
上一篇:


下一篇:索引monitoring可能会遇到的问题