Codeforces Round 1019 (Div. 2) A ~ D
A. Common Multiple
本质上是要求数组去重之后的长度。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, a[110];
bool vis[110];
inline void Solve() {
cin >> n, fill (vis, vis + n + 1, false);
for (int i = 1; i <= n; i ++)
cin >> a[i], vis[a[i]] = true;
int tot = 0;
for (int i = 1; i <= n; i ++)
tot += vis[i] ? 1 : 0;
cout << tot << "\n";
return;
}
signed main() {
ios_base::sync_with_stdio (false);
cin.tie (nullptr), cout.tie (nullptr);
int test; cin >> test;
while (test --)
Solve();
return 0;
}
B. Binary Typewriter
每次遇到相邻的两个不同的直接开始往左右扩散出极长连续 \(0/1\) 的子序列,如果整个串刚好是由一个极长连续 \(1\) 的子序列和极长连续 \(0\) 的子序列拼起来,那么只会一次更换按钮操作(一开始就统计 \(a_i \neq a_{i-1}\) 的个数),否则就可以通过翻转这个左右扩散出的极长连续 \(0/1\) 的子序列来减伤 \(2\) 次操作。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int test, n, a[200010];
inline void Solve() {
scanf ("%lld", &n);
for (int i = 1; i <= n; i ++) scanf ("%1lld", &a[i]);
int res = 0, ans = 0;
for (int i = 1; i <= n; i ++) res += (a[i] != a[i - 1]);
for (int i = 1; i <= n; i ++) {
if (a[i] != a[i - 1]) {
int posl = i - 1, posr = i;
while (~posl && a[posl] == a[i - 1]) posl --;
while (posr <= n && a[posr] == a[i]) posr ++;
ans = max (ans, 1LL * (~posl ? 1 : 0) + 1LL * (posr != n + 1 ? 1 : 0));
}
}
printf ("%lld\n", res + n - ans);
}
signed main() {
scanf ("%lld", &test);
while (test --) Solve();
return 0;
}
C. Median Splits
感觉像是乱搞过得。
如果说二分求中位数,那么可以对于 \(\leq mid\) 的数赋为 \(1\),\(\geq mid\) 的数,如果说两段加和为 \(0\) 那么 \(mid\) 就是中位数。
那么我们对于这题可以考虑处理前缀后缀(实则我是赛时打表以及注意力惊人发现),满足 \(\leq k\) 的数过半且记录最小的长度,
我们记 \(pre_i = \sum\limits_{j=1}^{i}{\begin{cases}1,a_i \leq k \\ -1,a_i > k\end{cases}}\),对于 \(pre_i \geq 0\),我们查询小于等于它的第一个,如果不是它自己,那么说明存在合法方案,因为此时中间那段的中位数也一定是 \(\leq k\) 的,后缀同理。
如果最后前后缀长度和 \(< n\) 也有解,此时中间那一段可能是只有一个数。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 2e5 + 10, INF = 0x7f7f7f7f7f7f;
int test, n, a[MAXN], pre[MAXN], b[MAXN], K;
map<int, int> mp;
inline void Solve() {
scanf ("%lld %lld", &n, &K);
for (int i = 1; i <= n; i ++) {
scanf ("%lld", &a[i]);
b[i] = (a[i] <= K ? 1 : -1);
pre[i] = pre[i - 1] + b[i];
}
int tmpX = INF, tmpY = INF;
mp.clear();
for (int i = 1; i <= n; i ++) {
if (pre[i] >= 0) {
if (tmpX == INF) tmpX = i;
if (mp.find (pre[i]) != mp.end()) mp[pre[i]] = min (mp[pre[i]], i);
else mp[pre[i]] = i;
int tmp = (-- mp.upper_bound (pre[i])) -> second;
if (tmp < i) return puts ("YES"), void();
}
}
reverse (b + 1, b + n + 1);
fill (pre + 1, pre + n + 1, 0), mp.clear();
for (int i = 1; i <= n; i ++) {
pre[i] = pre[i - 1] + b[i];
if (pre[i] >= 0) {
if (tmpY == INF) tmpY = i;
if (mp.find (pre[i]) != mp.end()) mp[pre[i]] = min (mp[pre[i]], i);
else mp[pre[i]] = i;
int tmp = (-- mp.upper_bound (pre[i])) -> second;
if (tmp < i) return puts ("YES"), void();
}
}
if (tmpX + tmpY >= n) puts ("NO");
else puts ("YES");
}
signed main() {
scanf ("%lld", &test);
while (test --) Solve();
return 0;
}
D. Local Construction
因为次序最多 \(\log n\),实则可以考虑枚举每次操作然后模拟。
这里只考虑对于奇数次序的操作,因为偶数同理。
奇数的情况我们考虑局部最小值,此时剩下的 \(a_i\) 一定小于两边的 \(a_{i-1},a_{i+1}\),当然删除的可能也是一段极长连续段,考虑小到大建边跑拓扑,对于连续极长的段我们相邻两个也建边。
拓扑序就是我们想要的答案。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 2e5 + 10, INF = 0x7f7f7f7f;
int test, n, a[MAXN], ls[MAXN], rs[MAXN], ans[MAXN];
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], indeg[MAXN], idx;
inline void Addedge (int u, int v) { indeg[v] ++, to[idx] = v, nxt[idx] = head[u], head[u] = idx ++; }
inline void tpSort() {
queue<int> q;
for (int i = 1; i <= n; i ++) if (!indeg[i]) q.push(i);
int index = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
ans[u] = ++ index;
for (int i = head[u]; ~i; i = nxt[i]) if (!--indeg[to[i]]) q.push (to[i]);
}
return;
}
inline void Solve() {
cin >> n, idx = 0;
for (int i = 1; i <= n; i ++) {
cin >> a[i], a[i] = (!~a[i]) ? INF : a[i];
ls[i] = i - 1, rs[i] = i + 1;
head[i] = -1, indeg[i] = 0;
}
for (int x = 1; x <= 20; x ++) {
for (int i = 1; i <= n; i ++) {
if (a[i] > x) {
if (x & 1) {
if (ls[i] >= 1 && ls[i] <= n) Addedge (i, ls[i]);
if (rs[i] >= 1 && rs[i] <= n) Addedge (i, rs[i]);
} else {
if (ls[i] >= 1 && ls[i] <= n) Addedge (ls[i], i);
if (rs[i] >= 1 && rs[i] <= n) Addedge (rs[i], i);
}
}
}
int posl = 0, posr = n + 1, st = n + 1, ed = 0;
for (int i = 1; i <= n; i ++) if (a[i] >= x) { st = i; break; }
for (int i = st; i <= n; i = rs[i]) if (a[i] != x) { posl = i; break; }
for (int i = st; i < posl; i = rs[i]) {
if (x & 1) Addedge (rs[i], i);
else Addedge (i, rs[i]);
}
for (int i = n; i >= 1; i --) if (a[i] >= x) { ed = i; break; }
for (int i = ed; i >= 1; i = ls[i]) if (a[i] != x) { posr = i; break; }
for (int i = ed; i > posr; i = ls[i]) {
if (x & 1) Addedge (ls[i], i);
else Addedge (i, ls[i]);
}
for (int i = rs[posl]; i < posr && i; i ++) {
if (a[i] == x && a[ls[i]] == x && a[rs[i]] == x)
Addedge (ls[i], i), Addedge (i, rs[i]);
}
for (int i = 1; i <= n; i ++) {
if (a[i] == x)
rs[ls[i]] = rs[i], ls[rs[i]] = ls[i];
}
}
tpSort();
for (int i = 1; i <= n; i ++)
cout << ans[i] << " \n"[i == n];
}
signed main() {
ios_base::sync_with_stdio (false);
cin.tie (nullptr), cout.tie (nullptr);
cin >> test;
while (test --)
Solve();
return 0;
}

浙公网安备 33010602011771号