Educational Codeforces Round 97 簡要題解
阿新 • • 發佈:2020-10-28
Educational Codeforces Round 97 簡要題解
預設源
#include <queue> #include <vector> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define MP make_pair #define ll long long #define fi first #define se second using namespace std; template <typename T> void read(T &x) { x = 0; bool f = 0; char c = getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=1; for (;isdigit(c);c=getchar()) x=x*10+(c^48); if (f) x=-x; } template<typename F> inline void write(F x, char ed = '\n') { static short st[30];short tp=0; if(x<0) putchar('-'),x=-x; do st[++tp]=x%10,x/=10; while(x); while(tp) putchar('0'|st[tp--]); putchar(ed); } template <typename T> inline void Mx(T &x, T y) { x < y && (x = y); } template <typename T> inline void Mn(T &x, T y) { x > y && (x = y); }
A. Marketing Scheme
直接判斷 \(l \times 2 \ge r\) 即可。
B. Reverse Binary Strings
這題讓好多人想了一會(我也,考慮對序列異或差分,最終序列要求全部事 1,每次 reverse 可以發現只有兩端的值變,所以每次可以同時消掉兩個 0
C. Chef Monocarp
簡單 dp 即可
D. Minimal Height Tree
模擬 bfs 即可,找到最長的連續段當作一串兒子掛在一個節點上。
const int N = 200050; int dep[N], a[N], T, n; int main() { for (read(T); T; T--) { read(n); memset(dep, 0, n * 4 + 200); queue<int> q; q.push(1); for (int i = 1;i <= n; i++) read(a[i]); for (int i = 2;i <= n; i++) { int t = q.front(); dep[i] = dep[t] + 1, q.push(i); if (a[i] >= a[i+1]) q.pop(); } write(dep[n]); } return 0; }
E. Make It Increasing
先考慮序列的合法情況,顯然嚴格上升序列可以通過 \(a[i] = a[i] - i\) 變成非嚴格上升序列,所以我們先正著反著掃兩遍,得出是否有解和哪些位置必須要改變,剩下的位置做最長上升子序列即可。
const int N = 500050; int st[N], a[N], vis[N], n, k, tp; void insert(int x) { if (!tp) return st[++tp] = x, void(); int l = 1, r = tp; while (l <= r) { int mid = (l + r) >> 1; if (st[mid] <= x) l = mid + 1; else r = mid - 1; } if (l > tp) st[++tp] = x; else st[l] = x; } int main() { read(n), read(k); for (int i = 1;i <= n; i++) read(a[i]), a[i] -= i; for (int i = 1, x;i <= k; i++) read(x), vis[x] = 1; int lim = -1e9; for (int i = 1;i <= n; i++) { if (vis[i] == 1) { if (a[i] < lim) return write(-1), 0; Mx(lim, a[i]); } if (a[i] < lim) vis[i] = -1; } lim = 1e9; for (int i = n;i >= 1; i--) { if (vis[i] == 1) { if (a[i] > lim) return write(-1), 0; Mn(lim, a[i]); } if (a[i] > lim) vis[i] = -1; } memset(st, 0x3f, sizeof(st)); st[tp = 0] = 0; for (int i = 1;i <= n; i++) { if (vis[i]) continue; insert(a[i]); } write(n - k - tp); return 0; }
F. Emotional Fishermen
考後自己補出來的。
假設我們已經獲得了最終的序列,把字首最大值看成隔板,首先兩個字首最大值 \(a_i, a_{i+1}\) 要滿足 \(2a_i\le a_{i+1}\),考慮其他元素 x,發現在第一個大於等於 \(2x\) 字首最大值之後就可以隨便填了。因此我們一個一個放字首最大值,每放一個最大值,發現有一些元素可以隨便放了,用排列算一下即可。
dp 的過程發現還可以字首和優化,吊打標算了
const int N = 5005;
const int P = 998244353;
ll fac[N], inv[N], pre[N], dp[N], a[N], n;
ll A(int n, int m) { return fac[n] * inv[n-m] % P; }
int cnt[N];
ll fpw(ll x, ll mi) {
ll res = 1;
for (; mi; mi >>= 1, x = x * x % P)
if (mi & 1) res = res * x % P;
return res;
}
int main() {
read(n);
for (int i = 1;i <= n; i++) read(a[i]);
fac[0] = 1;
for (int i = 1;i <= n; i++)
fac[i] = fac[i-1] * i % P;
inv[n] = fpw(fac[n], P - 2);
for (int i = n - 1; i >= 1; i--)
inv[i] = inv[i+1] * (i + 1) % P;
inv[0] = dp[0] = 1, sort(a + 1, a + n + 1);
int j = 0;
if (a[n-1] * 2 > a[n]) return write(0), 0;
for (int i = 1;i <= n; i++) {
while (j < n && a[j+1] * 2 <= a[i]) j++;
dp[i] = (A(n - 1, j) + pre[j] * inv[n - 1 - j]) % P;
pre[i] = (pre[i-1] + dp[i] * fac[n - j - 2]) % P;
}
write(dp[n]);
return 0;
}
G. Death DBMS
套路模板題,鏈剖 + AC 自動姬,考場上竟然碼出來了,我也是碼農
jly 有更好寫的 \(\Theta(n\sqrt n)\) 演算法,考慮暴力跳 fail,每次跳 fail 當前串長度都會減少 1,由於空節點的的值事 -1,我們直接跳過去,由於長度不同的串最多有 \(\sqrt n\) 個,所以複雜度正確。
const int N = 600050;
int ch[N][26], en[N], f[N], id[N], ed[N], cnt = 1;
char s[N];
inline void insert(char *s, int k) {
int p = 1, len = strlen(s + 1);
for (int i = 1;i <= len; i++) {
int c = s[i] - 'a';
if (!ch[p][c]) ch[p][c] = ++cnt;
p = ch[p][c];
}
en[k] = p, ed[p] = k;
}
int dep[N], siz[N], son[N], Top[N], dfn[N], num;
int h[N], ne[N<<1], to[N<<1], tot;
inline void add(int x, int y) { ne[++tot] = h[x], to[h[x] = tot] = y; }
void dfs(int x) {
dep[x] = dep[f[x]] + (siz[x] = 1);
for (int i = h[x], y; i; i = ne[i]) {
dfs(y = to[i]), siz[x] += siz[y];
if (siz[son[x]] < siz[y]) son[x] = y;
}
}
void dfs2(int x, int topf) {
Top[x] = topf, dfn[x] = ++num, id[num] = x;
if (son[x]) dfs2(son[x], topf);
for (int i = h[x], y; i; i = ne[i])
if ((y = to[i]) != son[x]) dfs2(y, y);
}
void build(void) {
queue<int> q;
for (int i = 0;i < 26; i++)
if (ch[1][i]) q.push(ch[1][i]), f[ch[1][i]] = 1;
else ch[1][i] = 1;
while (q.size()) {
int x = q.front(); q.pop();
if (x != 1) add(f[x], x);
for (int i = 0;i < 26; i++) {
if (!ch[x][i]) ch[x][i] = ch[f[x]][i];
else q.push(ch[x][i]), f[ch[x][i]] = ch[f[x]][i];
}
}
}
#define ls p << 1
#define rs ls | 1
int mx[N<<2];
void build(int p, int l, int r) {
mx[p] = -1;
if (l == r) return mx[p] = ed[id[l]] ? 0 : -1, void();
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
mx[p] = max(mx[ls], mx[rs]);
}
void change(int p, int l, int r, int x, int c) {
if (l == r) return mx[p] = c, void();
int mid = (l + r) >> 1;
if (x <= mid) change(ls, l, mid, x, c);
else change(rs, mid + 1, r, x, c);
mx[p] = max(mx[ls], mx[rs]);
}
void query(int p, int l, int r, int L, int R, int &ans) {
if (L <= l && r <= R) return Mx(ans, mx[p]);
int mid = (l + r) >> 1;
if (L <= mid) query(ls, l, mid, L, R, ans);
if (R > mid) query(rs, mid + 1, r, L, R, ans);
}
void query(int x, int &ans) {
while (x) {
query(1, 1, num, dfn[Top[x]], dfn[x], ans);
x = f[Top[x]];
}
}
struct Heap {
priority_queue<int> A, B;
void update(void) { while (B.size() && A.top() == B.top()) A.pop(), B.pop(); }
int Top(void) { update(); return A.top(); }
void del(int x) { B.push(x); }
void push(int x) { A.push(x); }
}q[300005];
int pre[N], n, m;
int main() {
read(n), read(m);
for (int i = 1;i <= n; i++)
scanf ("%s", s + 1), insert(s, i), q[en[i]].push(0);
build(), dfs(1), dfs2(1, 1), build(1, 1, num);
for (int i = 1, x, y;i <= m; i++) {
int op; read(op);
if (op == 1) {
read(x), read(y);
q[en[x]].push(y), q[en[x]].del(pre[x]), pre[x] = y;
change(1, 1, num, dfn[en[x]], q[en[x]].Top());
}
else {
scanf ("%s", s + 1);
int len = strlen(s + 1), nw = 1, ans = -1;
for (int i = 1;i <= len; i++) {
nw = ch[nw][s[i] - 'a'];
query(nw, ans);
}
write(ans);
}
}
return 0;
}