牛客练习赛85

牛客练习赛85

A - 科学家的模型

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    string s[5];
    for (int i = 0; i < 5; ++i)
        cin >> s[i];
 
    int x = -1, y, ans = 0;
    for (int i = 0; i < 5 && x == -1; ++i)
        for (int j = 0; j < 5 && x == -1; ++j)
            if (s[i][j] == '1') x = i, y = j;
 
    int len = 0;
    while (y + len < 5 && s[x][y + len] == '1')
        ++len;
 
    for (int i = x + 1; i < 5; ++i) {
        if (s[i][y + 1] == '1' && i < 4 && s[i + 1][y] == '1') ans = 8;
        if (s[i][y] ^ s[i][y + len - 1]) ans = 9;
        if (s[i][y] == '0' && s[i][y + len - 1] == '0') break;
    }
 
    cout << ans;
    return 0;
}

B - 科学家的模型

尺取, 让你找三段,

那就枚举中间的一段, 预处理左边的和右边的即可

预处理用到尺取

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    int n, m, ans = 0;
    string s;
    cin >> n >> m >> s;
 
    vector<int> cnt(26), l(n), r(n);
 
    for (int i = 0, j = 0; i < n; ++i) {
        ++cnt[s[i] - 'a'];
 
        while (cnt[s[i] - 'a'] > m && j <= i)
            --cnt[s[j++] - 'a'];
 
        l[i] = i ? max(l[i - 1], i - j + 1) : i - j + 1;
    }
 
    cnt.assign(cnt.size(), 0);
    for (int i = n - 1, j = n - 1; ~i; --i) {
        ++cnt[s[i] - 'a'];
 
        while (cnt[s[i] - 'a'] > m && i >= i)
            --cnt[s[j--] - 'a'];
 
        r[i] = i != n - 1 ? max(r[i + 1], j - i + 1) : j - i + 1;
        ans = max(ans, (i ? l[i - 1] : 0) + j - i + 1 + (i != n - 1 ? r[j + 1] : 0));
    }
 
    cout << ans;
    return 0;
}

C - 哲学家的沉思

典型的倍增题, 复杂度\(O(nlogn)\)

先倍增, 预处理

\(mx(i, j)\) 表示区间 \([i, max(i + 2^j, n)]\) 的最大值

在通过\(mx(i, j)\) 预处理st表的\(st(i, 0)\)

\(st(i, j)\) 表示从位置\(i\)开始包含\(2^j\)个区间能到达最远的右端点(左闭右开)

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int n, q, ans = 0;
    cin >> n >> q;
    
    vector<int> a(n);
    for (auto &i : a) cin >> i;

    vector<vector<int>> mx(n, vector<int>(17));
    for (int i = 0; i < n - 1; ++i)
        mx[i][0] = max(a[i], a[i + 1]);
    mx[n - 1][0] = 2e9;

    for (int j = 1; j < 17; ++j)
        for (int i = 0; i < n; ++i)
            mx[i][j] = max(mx[i][j - 1], mx[min(i + (1 << j - 1), n - 1)][j - 1]);

    vector<vector<int>> st(n + 1, vector<int>(17));
    for (int i = 0; i < n; ++i) {
        int r = i;
        for (int j = 16; ~j; --j)
            if (mx[r][j] <= a[i])
                r += 1 << j;
        st[i][0] = r + 1;
    }
    st[n][0] = n;
    
    for (int j = 1; j < 17; ++j)
        for (int i = 0; i <= n; ++i)
            st[i][j] = st[st[i][j - 1]][j - 1];

    while (q--) {
        int l, r, ans = 1;
        cin >> l >> r;
        --l, --r;

        for (int i = 16; i >= 0; --i)
            if (st[l][i] <= r)
                ans += 1 << i, l = st[l][i];

        cout << ans << '\n';
    }
    return 0;
}

用bitset维护所含的质数

线段树维护区间bitset即可

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

struct BIT {
    static const int N = 5e4 + 5;
    bitset<M> tr[N << 2];

    void push_up(int p) {
        tr[p] = tr[p << 1] | tr[p << 1 | 1];
    }

    void change(int p, int l, int r, int k, bitset<M> &v) {
        if (l == k && r == k) {
            tr[p] = v;
            return;
        }
        int mid = l + r >> 1;
        if (mid >= k) change(p << 1, l, mid, k, v);
        else change(p << 1 | 1, mid + 1, r, k, v);
        push_up(p);
    }

    bitset<M> ask(int p, int l, int r, int L, int R) {
        if (L <= l && r <= R) return tr[p];
        int mid = l + r >> 1;
        if (mid >= R) return ask(p << 1, l, mid, L, R);
        if (mid < L) return ask(p << 1 | 1, mid + 1, r, L ,R);
        return ask(p << 1, l, mid, L, R) | ask(p << 1 | 1, mid + 1, r, L, R);
    }
} bit;

int pri[M], tot;
bool v[N];
bitset<M> ve;

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

void setbit(int n) {
    ve = 0;
    for (int i = 0; pri[i] <= n / pri[i]; ++i)
        if (n % pri[i] == 0) {
            ve[i] = 1;
            while (n % pri[i] == 0) n /= pri[i];
        }
    if (n - 1)
        ve[lower_bound(pri, pri + tot, n) - pri] = 1;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    init(1e5);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        setbit(x);
        bit.change(1, 1, n, i, ve);
    }

    while (m--) {
        int op, x, y;
        cin >> op >> x >> y;

        if (op == 1) {
            setbit(y);
            bit.change(1, 1, n, x, ve);
        }
        else
            cout << bit.ask(1, 1, n, x, y).count() << '\n';
    }
    return 0;
}
posted @ 2021-07-06 23:06  洛绫璃  阅读(50)  评论(0编辑  收藏  举报