Codeforces Round #321 (Div. 2)
A. Kefa and First Steps
求最长递增连续子序列。
B. Kefa and Company
排序二分就行了。
#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; }
C. Kefa and Park
#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); }
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)$
#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; }
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咋改都没用。
然后用了两个模数才行。
#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; }