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;
}
