牛客练习赛70

# A
就是找最短区间存在这10个字母呗, O(n)

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;
 
template<class T> bool umin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool umax(T &a, T b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T &a) { T().swap(a); }
 
const int N = 1e5 + 5;
 
int n, m, _, k;
char s[N], t[] = "puleyaknoi";
int v[10];
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> s + 1; int cnt = 0, ans = 1e9;
        rep (i, 0, 9) v[i] = 0;
        for (int i = 1; s[i]; ++i) {
            rep (j, 0, 9)
                if (s[i] == t[j]) { cnt += !v[j], v[j] = i; break; }
            if (cnt == 10) {
                int mi = 1e9, mx = 0;
                rep (j, 0, 9) umin(mi, v[j]), umax(mx, v[j]);
                umin(ans, mx - mi + 1);
            }
        }
        if (ans == 1e9) cout << "-1\n";
        else cout << ans << '\n';
    }
    return 0;
}

B

二分呗, 提前记录 字母 'p' 出现的位置作为二分判定的起点

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;
 
template<class T> bool umin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool umax(T &a, T b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T &a) { T().swap(a); }
 
const int N = 1e5 + 5;
 
int n, m, _, k;
char s[N], t[] = "puleyaknoi";
VI c;
 
bool check(int mid) {
    for (int &a : c) {
        int cnt = 0;
        for (int i = a; t[cnt] && i - a + 1 <= mid && s[i]; ++i)
            if (s[i] == t[cnt]) ++cnt;
        if (cnt == 10) return 1;
    }
    return 0;
}
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> s; clear(c);
        for (int i = 0; s[i]; ++i) if (s[i] == 'p') c.pb(i);
        int l = 10, r = 1e5 + 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid)) r = mid;
            else l = mid + 1;
        }
        if (r == 1e5 + 1) cout << "-1\n";
        else cout << r << '\n';
    }
    return 0;
}

C

存在 两个节点的环, 找一下就好了, 就两个系节点的环

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

template<class T> bool umin(T& a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool umax(T& a, T b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 1e7 + 10;

int n, m, _, k;
int prime[N], miu[N], tot;
bool v[N];

void init(int n) {
    miu[1] = 1;
    rep (i, 2, n) {
        if (!v[i]) prime[++tot] = i, miu[i] = -1;
        for (int j = 1; prime[j] <= n / i && j <= tot; ++j) {
            v[prime[j] * i] = 1;
            if(i % prime[j] == 0) { miu[i * prime[j]] = 0; break; }
            else miu[i * prime[j]] = -miu[i];
        }
    }
}

int main() {
    IOS; init(1e7);
    for (cin >> _; _; --_) {
        ll m; cin >> n >> m;
        bool f1 = 0, f2 = 0;
        for (int c = 0; miu[n] != 0 && m; --m) {
            if (f1 && f2) {
                if (m & 1) n += c;
                break;
            }
            if (miu[n] == 1) f1 = 1, c = -1;
            else f2 = 1, c = 1;
            n += miu[n];
        }
        cout << n << '\n';
    }
    return 0;
}

D

用不着离散化, 也不用存谁连谁, 用map存下 哪个节点连了几条边就好了, 用 set存边 (min(u, v), max(u,v)) 存这条就行

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

template<class T> bool umin(T& a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool umax(T& a, T b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 1e5 + 5;

int n, m, _, k;
unordered_map<int, int> st;
set<PII> s;

int main() {
    IOS; cin >> n;
    rep(i, 1, n) {
        cin >> m;
        if (m == 3) cout << k << '\n';
        else if (m == 1) {
            int u, v; cin >> u >> v;
            if (u > v) swap(u, v);
            if (s.count({ u, v })) continue;
            int a = ++st[u], b = ++st[v];
            if (a == 1 && b == 1) ++k;
            else if (min(a, b) > 1) --k;
            s.insert({ u, v });
        }
        else {
            int u, v; cin >> u >> v;
            if (u > v) swap(u, v);
            if (!s.count({ u, v })) continue;
            int a = --st[u], b = --st[v]; 
            if (!a && !b) --k;
            else if (a && b) ++k;
            s.erase({ u, v });
        }
    }
    return 0;
}

F

区间操作, 求的是区间和绝对值最小, 那先求一下前缀和呗

那么对于 (l, r) 就是求 [l - 1, r - 1] 中谁和 sum[r] 差值最小呗

我们卡着 r, 求出对于 i ∈ [1, r - 1], abs(sum[r] - sum[i]) 最小, 离线回答就好了

这不是明显的线段树吗, 然后我就不会了

我是真没想到, 还能在每个节点存下 sum[l] ~ sum[r] 的

而且这道题 tag 是不能叠加的, 必须一次 push_down 到底, 那么必然超时

所以我们在 change 的时候 先处理右区间并记录最小的 abs, 那么在递归回来求左区间的时候, 一旦 大于 最小值 直接 return

答案对于从右向左是单调的, 最小值出现在靠近 r 的点上, 谁还管远处的点?

这每个节点存sum[l]~sum[r], 和 根据单调贪心减小复杂度 是真的秀

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 1e5 + 5, M = 3e5 + 5;

int n, m, _, k;
ll a[N], ans[M], mi;

struct tree {
    struct node {
        int l, r;
        ll val = 2e18;
        vector<ll> c;
    } tr[N << 2];

    void push_up(int rt) {
        umin(tr[rt].val, min(tr[rt << 1].val, tr[rt << 1 | 1].val));
    }

    void build(int rt, int l, int r) {
        tr[rt].l = l; tr[rt].r = r; tr[rt].c.resize(r - l + 1);
        rep(i, l, r) tr[rt].c[i - l] = a[i];
        sort(all(tr[rt].c));
        if (l == r) return;
        int mid = l + r >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
    }

    bool solve(int rt, ll k) {
        auto it = upper_bound(all(tr[rt].c), k);
        if (it != tr[rt].c.begin()) umin(tr[rt].val, k - *(it - 1));
        if (it != tr[rt].c.end()) umin(tr[rt].val, *it - k);
        if (mi <= tr[rt].val) return 1;
        if (tr[rt].l == tr[rt].r) { umin(mi, tr[rt].val); return 1; }
        return 0;
    }

    void change(int rt, int p, ll k) {
        if (tr[rt].r <= p) { if (solve(rt, k)) return; }
        int mid = tr[rt].l + tr[rt].r >> 1;
        if (mid < p) change(rt << 1 | 1, p, k);
        change(rt << 1, p, k);
        push_up(rt);
        mi = min(mi, tr[rt].val);
    }

    ll ask(int rt, int l, int r) {
        if (tr[rt].l >= l && tr[rt].r <= r) return tr[rt].val;
        int mid = tr[rt].l + tr[rt].r >> 1;
        if (mid >= r) return ask(rt << 1, l, r);
        else if (mid < l) return ask(rt << 1 | 1, l, r);
        else return min(ask(rt << 1, l, r), ask(rt << 1 | 1, l, r));
    }
} bit;

pair<int, PII> q[M];

int main() {
    IOS; cin >> n >> m; ++n;
    rep(i, 2, n) cin >> a[i];
    rep(i, 2, n) a[i] += a[i - 1];
    bit.build(1, 1, n);
    rep(i, 1, m) {
        cin >> q[i].se.fi >> q[i].fi;
        q[i].se.se = i; ++q[i].fi;
    }
    sort(q + 1, q + 1 + m);
    for (int i = 2, j = 1; i <= n; ++i) {
        mi = 2e18;
        bit.change(1, i - 1, a[i]);
        while (j <= m && q[j].fi <= i) ans[q[j].se.se] = bit.ask(1, q[j].se.fi, i), ++j;
    }
    rep(i, 1, m) cout << ans[i] << '\n';
    return 0;
}
上一篇:IPv6


下一篇:Python06-09_序列----列表元素的访问和计数