人生中第三次$CF$。。。 考試中切了$A$~$E$ $F$題會作沒時間寫c++
#題解 ##A:Points on the line ###題意 給定一個數列,刪最小的數,使最大差不大於一個定值 ###Sol 排序後選的必定是段連續的區間,枚舉左右端點便可算法
手速慢了233spa
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(105); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, d, x[_], ans; int main(RG int argc, RG char* argv[]){ n = Input(), d = Input(); for(RG int i = 1; i <= n; ++i) x[i] = Input(); sort(x + 1, x + n + 1); if(!n || x[n] - x[1] <= d) return puts("0"), 0; for(RG int i = 1; i <= n; ++i) for(RG int j = i; j <= n; ++j) if(x[j] - x[i] <= d) ans = max(ans, j - i + 1); printf("%d\n", n - ans); return 0; }
##B:Our Tanya is Crying Out Loud ###題意 給定數$n$和$k$以及代價$A$和$B$ 你能夠花$A$的代價給$n$減$1$ 或者當$n$爲$k$的倍數時花$B$的代價把$n$變爲$n/k$ 問$n$變爲$1$的最小代價 ###Sol 不是$k$的倍數,就減到$k$的倍數爲止 不然比較減和除的代價,取最小code
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(105); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, k, a, b; ll ans = 0; int main(RG int argc, RG char* argv[]){ n = Input(), k = Input(), a = Input(), b = Input(); if(k == 1){ cout << 1LL * a * (n - 1) << endl; return 0; } while(n >= k){ RG int t = n / k, tt = n % k; n -= tt; ans += 1LL * tt * a; ans += min(1LL * b, 1LL * (n - t) * a); n = t; } ans += 1LL * a * (n - 1); cout << ans << endl; return 0; }
##C:Phone Numbers ###題意 一個長度爲$n$的小寫字母組成的字符串和一個整數$k$,要你生成一個最小字典序的長度爲$k$的小寫字母組成的字符串 使該字符串的字符集爲給定串的字符集的子集,而且字典序大於給定串 ###Sol 找到一個最後面的位置能夠使答案串大於原串,後面直接填最小的字符排序
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(1e5 + 5); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, k, t[30], pos, g[30]; char s[_]; int main(RG int argc, RG char* argv[]){ n = Input(), k = Input(); scanf(" %s", s + 1), s[n + 1] = 'a' - 1; for(RG int i = 1; i <= n; ++i) ++t[s[i] - 'a']; for(RG int i = 25; ~i; --i) g[i] = t[i], t[i] += t[i + 1]; for(RG int i = min(k, n + 1); i; --i) if(t[s[i] - 'a' + 1]){ pos = i; break; } for(RG int i = 1; i < pos; ++i) printf("%c", s[i]); for(RG int i = s[pos] - 'a' + 1; i < 26; ++i) if(g[i]){ printf("%c", i + 'a'); break; } RG int tmp = 0; for(RG int i = 0; i < 26; ++i) if(g[i]){ tmp = i; break; } for(RG int i = pos + 1; i <= k; ++i) printf("%c", tmp + 'a'); return 0; }
##D:Alena And The Heater ###題意 給定數列$A$ 以及生成數列$B$的條件: $B[1]=B[2]=B[3]=B[4]=0$ 對於$i>4$ 若是 $a[i],a[i-1],a[i-2],a[i-3],a[i-4]>r$ 且$b[i-1]=b[i-2]=b[i-3]=b[i-4]=1$ 則$b[i]=1$ 若是 $a[i],a[i-1],a[i-2],a[i-3],a[i-4]<l$ 且$b[i-1]=b[i-2]=b[i-3]=b[i-4]=0$ 則$b[i]=0$ 不然$b[i]=b[i-1]$ 保證必定有解,輸出$l, r$能夠構造出給定的數列$B$ 輸出任意一組$l,r\in[-1e9, 1e9]$ ###Sol 保證必定有解,那麼按題意反過來構造$l, r$便可字符串
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(1e5 + 5); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, a[_], b[_], l = -1e9, r = 1e9; char s[_]; int main(RG int argc, RG char* argv[]){ n = Input(); for(RG int i = 1; i <= n; ++i) a[i] = Input(); scanf(" %s", s + 1); for(RG int i = 1; i <= n; ++i) b[i] = s[i] - '0'; for(RG int i = 5; i <= n; ++i){ RG int s = b[i - 1] + b[i - 2] + b[i - 3] + b[i - 4]; if(s && s != 4) continue; if(b[i] == b[i - 1]) continue; if(b[i]){ RG int mx = -1e9; for(RG int j = 0; j <= 4; ++j) mx = max(mx, a[i - j]); l = max(l, mx + 1); } else{ RG int mn = 1e9; for(RG int j = 0; j <= 4; ++j) mn = min(mn, a[i - j]); r = min(r, mn - 1); } } printf("%d %d\n" ,l, r); return 0; }
##E:Cashback ###題意 給定一個長度爲$n$的數列以及一個整數$c$ 一個下標在$[l, r]$內的子數列的價值爲全部數的和減去子數列中前$\lfloor\frac{r-l+1}{c}\rfloor$小的數的和 求把這個數列分紅若干個塊,使的每塊的價值和最小 ###Sol 前$k$小?離散化+主席樹辣 碼完 發現只會$n^2$的滴劈 設$f[i]$表示作到第$i$個數的最小代價,枚舉長度轉移,前$k$小的和主席樹查詢 你當這是$OI$賽制啊?沒有部分分的。。 咱們分狀況考慮get
那麼策略就是:要麼一個一個選,要麼選$c$個一塊 只要求區間最小值,$RMQ$問題 然而主席樹懶得刪it
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(1e5 + 5); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, c, tot, len, rt[_]; ll f[_], s[_], o[_], a[_]; struct HJT{ int sz, rs, ls; ll sum; } T[_ * 20]; IL void Modify(RG int &x, RG int l, RG int r, RG int id, RG ll v){ T[++tot] = T[x], T[x = tot].sum += v, ++T[x].sz; if(l == r) return; RG int mid = (l + r) >> 1; if(id <= mid) Modify(T[x].ls, l, mid, id, v); else Modify(T[x].rs, mid + 1, r, id, v); } IL ll Query(RG int A, RG int B, RG int l, RG int r, RG int k){ if(l == r) return o[l]; RG int mid = (l + r) >> 1, ss = T[T[B].ls].sz - T[T[A].ls].sz; RG ll sss = T[T[B].ls].sum - T[T[A].ls].sum; if(ss >= k) return Query(T[A].ls, T[B].ls, l, mid, k); else return sss + Query(T[A].rs, T[B].rs, mid + 1, r, k - ss); } int main(RG int argc, RG char* argv[]){ n = Input(), c = Input(), Fill(f, 127), f[0] = 0; for(RG int i = 1; i <= n; ++i) o[i] = a[i] = Input(), s[i] = s[i - 1] + a[i]; sort(o + 1, o + n + 1), len = unique(o + 1, o + n + 1) - o - 1; for(RG int i = 1; i <= n; ++i){ RG int p = lower_bound(o + 1, o + len + 1, a[i]) - o; rt[i] = rt[i - 1], Modify(rt[i], 1, len, p, a[i]); } for(RG int i = 1; i < c; ++i) f[i] = s[i]; for(RG int i = c; i <= n; ++i){ RG ll sum = s[i] - s[i - c] - Query(rt[i - c], rt[i], 1, len, 1); f[i] = min(f[i - 1] + a[i], f[i - c] + sum); } cout << f[n] << endl; return 0; }
##F:Machine Learning ###題意 給一個數列 每次詢問一個區間$[l,r]$ 求數列下標在這個區間內的數的個數的$mex$值 $p.s$:$mex$值是最小的沒出現的整數值 數會隨時修改 ###Sol 這不就是離散化+帶修改莫隊嗎? 吐槽一下: $mex$值開桶暴力求就能過了class
個人作法: 把數字也分塊,計算$mex$時,找到第一個不滿的塊,再在塊內找的那個$mex$值gc
還有一點就是 我$TM$學了假的帶修改莫隊: 沒按時間爲第三關鍵字排序!!! 沒把塊的大小設爲$n^\frac{2}{3}$!!! 沒比較右端點所在的塊!!! 而後一直$TLE$,$QAQ$
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(4e5 + 5); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, q, bl[_], o[_], len, a[_], ans[_], blo, cnt, tot; int t[_], sum[5000], size[_]; struct Query{ int l, r, t, id; IL bool operator <(RG Query B) const{ if(bl[l] != bl[B.l]) return l < B.l; if(bl[r] != bl[B.r]) return r < B.r; return t < B.t; } } qry[_]; struct Modify{ int p, x; } mdy[_]; IL void Change(RG int x, RG int d){ if(d > 0){ if(!size[x]) ++sum[x / blo]; ++size[x]; } else{ --size[x]; if(!size[x]) --sum[x / blo]; } } IL int Mex(){ for(RG int i = 0; ; ++i) if(sum[i] != blo){ for(RG int j = 0; j < blo; ++j) if(!size[i * blo + j]) return i * blo + j; } } IL void Calc(RG int v, RG int d){ Change(t[v], -1), t[v] += d, Change(t[v], 1); } IL void Adjust(RG int j, RG int l, RG int r){ if(mdy[j].p >= l && mdy[j].p <= r) Calc(a[mdy[j].p], -1); swap(a[mdy[j].p], mdy[j].x); if(mdy[j].p >= l && mdy[j].p <= r) Calc(a[mdy[j].p], 1); } int main(RG int argc, RG char* argv[]){ n = Input(), q = Input(), blo = pow(n, 2.0 / 3.0); for(RG int i = 1; i <= n; ++i) o[++len] = a[i] = Input(), bl[i] = (i - 1) / blo; for(RG int i = 1; i <= q; ++i){ RG int op = Input(), x = Input(), y = Input(); if(op == 1) qry[++cnt] = (Query){x, y, tot, cnt}; else mdy[++tot] = (Modify){x, y}, o[++len] = y; } sort(o + 1, o + len + 1), len = unique(o + 1, o + len + 1) - o - 1; for(RG int i = 1; i <= n; ++i) a[i] = lower_bound(o + 1, o + len + 1, a[i]) - o; for(RG int i = 1; i <= tot; ++i) mdy[i].x = lower_bound(o + 1, o + len + 1, mdy[i].x) - o; sort(qry + 1, qry + cnt + 1), blo = sqrt(len); for(RG int L = qry[1].l, R = qry[1].l - 1, i = 1, j = 0; i <= cnt; ++i){ while(L < qry[i].l) Calc(a[L++], -1); while(L > qry[i].l) Calc(a[--L], 1); while(R < qry[i].r) Calc(a[++R], 1); while(R > qry[i].r) Calc(a[R--], -1); while(j < qry[i].t) Adjust(++j, L, R); while(j > qry[i].t) Adjust(j--, L, R); ans[qry[i].id] = Mex(); } for(RG int i = 1; i <= cnt; ++i) printf("%d\n", ans[i]); return 0; }
#總結 $CF$比賽的題仍是不錯的 總有一些奇奇怪怪的腦洞 話說歪果仁知道主席樹和莫隊算法嗎?