Codeforces Round #321 (Div. 2)

A. Kefa and First Steps

求最长递增连续子序列。

 

B. Kefa and Company

排序二分就行了。

Codeforces Round #321 (Div. 2)
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e5 + 7;

struct P {
    ll m, s;
    P(ll m = 0, ll s = 0): m(m), s(s) {}
    bool operator < (const P &rhs) const {
        return m < rhs.m;
    }
} p[N];

ll sum[N];

int main() {
    int n;
    ll d;
    scanf("%d%lld", &n, &d);
    for (int i = 1; i <= n; i++)
        scanf("%lld%lld", &p[i].m, &p[i].s);
    sort(p + 1, p + n + 1);
    ll ans = 0;
    for (int i = 1; i <= n; i++) 
        sum[i] = sum[i - 1] + p[i].s;
    for (int i = 1; i <= n; i++) {
        int pos = upper_bound(p + i + 1, p + n + 1, P(d + p[i].m - 1, 0)) - p;
        pos--;
        if (pos < i) continue;
        ans = max(ans, sum[pos] - sum[i - 1]);
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

 

C. Kefa and Park

Codeforces Round #321 (Div. 2)
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 7;
vector<int> G[N];
int n, m, ans;
int havecat[N];

void dfs(int u, int fa, int con) {
    if (G[u].size() == 1) {
        if (con <= m) ans++;
        return;
    }
    for (auto v: G[u]) {
        if (v == fa) continue;
        if (!havecat[v]) dfs(v, u, 0);
        else if (con + 1 <= m) dfs(v, u, con + 1);
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) 
        scanf("%d", &havecat[i]);
    for (int i = 1, u, v; i < n; i++) {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    G[1].push_back(0);
    dfs(1, 0, havecat[1]);
    printf("%d\n", ans);
}
View Code

 

D. Kefa and Dishes

显然状压,因为吃了一些菜品之后,只跟最后一个吃的是哪一个有关,即一个集合只跟最后一个加入的元素有关。
$dp[s][i]$ 表示吃了集合 $s$ 的菜品,最后一个吃的是第 $i$ 个菜品。
转移 $dp[s | (1 << j)] = dp[s] + a[j] + c[i][j]$
吃了 $m$ 个菜品就在转移过程中计算就行了。
复杂度 $O(n^2 2^n)$

Codeforces Round #321 (Div. 2)
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 18;
const int sz = (1 << N) + 1;

ll mp[N][N], dp[sz][N], a[N];

inline int getone(int s) {
    int cnt = 0;
    while (s) {
        cnt++;
        s &= (s - 1);
    }
    return cnt;
}

template<class T>
inline void checkmax(T &a, T b) {
    if (a < b) a = b;
}

int main() {
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    memset(dp, -1, sizeof(dp));
    for (int i = 0; i < n; i++) 
        scanf("%lld", &a[i]), dp[1 << i][i] = a[i];
    for (int i = 0; i < k; i++) {
        int u, v; ll c;
        scanf("%d%d%lld", &u, &v, &c);
        u--, v--;
        mp[u][v] = c;
    }
    int S = 1 << n;
    ll ans = 0;
    for (int s = 1; s < S; s++)
        for (int i = 0; i < n; i++) if ((s >> i & 1) && dp[s][i] >= 0) {
            if (getone(s) == m) checkmax(ans, dp[s][i]);
            for (int j = 0; j < n; j++) if (!(s >> j & 1)) 
                checkmax(dp[s | (1 << j)][j], dp[s][i] + a[j] + mp[i][j]);
        }
    printf("%lld\n", ans);
    return 0;
}
View Code

 

E. Kefa and Watch

题意:
给一个数字串。操作一为区间修改。操作二询问一个区间是否周期为 $d$

思路:
判断周期可以用哈希。
相当于有 $|s| - d$ 个等式。
$s[l] = s[l + d]$
$s[l + 1] = s[l + d + 1]$
$\dots$
$s[r - d] = s[r]$
把左边和右边分别拼起来就是判 $[l, r - d]$ 和 $[l + d, r]$ 相同
那么线段树维护哈希值即可。
刚开始用自然溢出,两个seed咋改都没用。
然后用了两个模数才行。

Codeforces Round #321 (Div. 2)
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;

const int N = 1e5 + 7;
int n, m, k;
char s[N];

struct Seg {
    #define lp p << 1
    #define rp p << 1 | 1
    ull tree[N * 4], bit[N], sum[N], seed, MOD;
    int lazy[N * 4];
    inline void init() {
        for (int i = bit[0] = sum[0] = 1; i < N; i++) {
            bit[i] = (bit[i - 1] * seed) % MOD;
            sum[i] = (sum[i - 1] + bit[i]) % MOD;
        }
        build(1, 1, n);
    }
    inline void pushup(int p, int llen, int rlen) {
        tree[p] = (tree[lp] * bit[rlen] % MOD + tree[rp]) % MOD;
    }
    inline void tag(int p, int dig, int len) {
        lazy[p] = dig;
        tree[p] = sum[len - 1] * dig % MOD;
    }
    inline void pushdown(int p, int llen, int rlen) {
        if (lazy[p] >= 0) {
            tag(lp, lazy[p], llen);
            tag(rp, lazy[p], rlen);
            lazy[p] = -1;
        }
    }
    void build(int p, int l, int r) {
        lazy[p] = -1;
        if (l == r) {
            tree[p] = s[l] - '0';
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p, mid - l + 1, r - mid);
    }
    void update(int p, int l, int r, int x, int y, int dig) {
        if (x <= l && y >= r) {
            lazy[p] = dig;
            tree[p] = dig * sum[r - l] % MOD;
            return;
        }
        int mid = l + r >> 1;
        pushdown(p, mid - l + 1, r - mid);
        if (x <= mid) update(lp, l, mid, x, y, dig);
        if (y > mid) update(rp, mid + 1, r, x, y, dig);
        pushup(p, mid - l + 1, r - mid);
    }
    ull query(int p, int l, int r, int x, int y) {
        if (x > y) return 0;
        if (x <= l && y >= r) return tree[p];
        int mid = l + r >> 1;
        pushdown(p, mid - l + 1, r - mid);
        if (y <= mid) return query(lp, l, mid, x, y);
        if (x > mid) return query(rp, mid + 1, r, x, y);
        return (query(lp, l, mid, x, y) * bit[min(y, r) - (mid + 1) + 1] % MOD + query(rp, mid + 1, r, x, y)) % MOD;
    }
} seg[2];

int main() {
    scanf("%d%d%d", &n, &m, &k);
    m += k;
    scanf("%s", s + 1);
    seg[0].seed = 233; seg[0].MOD = 201326611;
    seg[1].seed = 2333; seg[1].MOD = 402653189;
    seg[0].init(); seg[1].init();
    for (int opt, l, r, d; m--; ) {
        scanf("%d%d%d%d", &opt, &l, &r, &d);
        if (opt == 1) {
            for (int i = 0; i < 2; i++)
                seg[i].update(1, 1, n, l, r, d);
        } else {
            if (r - l + 1 == d || (seg[0].query(1, 1, n, l, r - d) == seg[0].query(1, 1, n, l + d, r) && seg[1].query(1, 1, n, l, r - d) == seg[1].query(1, 1, n, l + d, r))) {
                puts("YES");
            } else {
                puts("NO");
            }
        }
    }
    return 0;
}
View Code

 

上一篇:线段树(区间查询,区间修改)——标记永久化版


下一篇:139. 单词拆分