A - Avoid Trygub
int main() {
IOS;
for (cin >> _; _; --_) {
string s; cin >> n >> s;
sort(all(s)); cout << s << '\n';
}
return 0;
}
B - Balls of Steel
枚舉找就完事
PII a[N];
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> k;
rep (i, 1, n) cin >> a[i].fi >> a[i].se;
int ans = -1;
rep (i, 1, n) {
bool f = 0;
rep (j, 1, n) if (abs(a[i].fi - a[j].fi) + abs(a[i].se - a[j].se) > k) { f = 1; break; }
if (!f) { ans = 1; break; }
}
cout << ans << '\n';
}
return 0;
}
C1 & C2 - Errich-Tac-Toe
明顯是考慮(i + j) % 3, 記 ++cnt[(i + j) % 3][s[i][j] == 'X']
最后無非選擇 i, j(-1<i,j<3, i!=j) 使得 s[i][1] + s[j][0] <= k/3, 即使得每3個相鄰的標記中存在兩個不同的標記
一定存在這樣的 i, j使得 <= k/3, 自己畫個表就明白了
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n; memset(c, 0, sizeof c);
rep (i, 0, n - 1) {
cin >> s[i];
rep (j, 0, n - 1) if (s[i][j] != '.') ++c[(i + j) % 3][s[i][j] == 'X'], ++k;
}
rep (i, 0, 2) rep (j, 0, 2) if (i != j && c[i][1] + c[j][0] <= k / 3) {
rep (x, 0, n - 1) rep (y, 0, n - 1) if (s[x][y] != '.')
if ((x + y) % 3 == i) s[x][y] = 'O';
else if ((x + y) % 3 == j) s[x][y] = 'X';
k = 0;
}
rep (i, 0, n - 1) cout << s[i] << '\n';
}
return 0;
}
D - Rating Compression
md, 向獲取 a[i] 能被選出來的范圍 l~r, 用了線段樹+倍增 t7
直接單調棧不好嗎? 不過cf \(nlog^2n\) 常數稍大點竟然過不去, 離譜
nt a[N], b[N], l[N];
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n;
rep(i, 1, n) cin >> a[i], b[i] = 0;
stack<PII> q;
rep(i, 1, n) {
while (!q.empty() && q.top().fi >= a[i]) umax(b[q.top().fi], i - l[q.top().se]), q.pop();
if (q.empty()) l[i] = 1;
else l[i] = q.top().se + 1;
q.push({ a[i], i });
}
while (!q.empty()) umax(b[q.top().fi], n + 1 - l[q.top().se]), q.pop();
rep(i, 2, n) umin(b[i], b[i - 1]);
rep(i, 1, n) cout << (b[n - i + 1] >= i); cout << '\n';
}
return 0;
}
E - Capitalism
建圖跑個多源最短路就好,
b = 1, d[u][v] = 1, d[v][u] = -1;
b = 0, d[u][v] = d[v][u] = 1;
分別跑出來以 i 為最少的資本, 的最短路
找到以誰為起點s, 差值最大就行
判 no, 就對於 d[s][u] == d[s][v] 為 no 就行
順便用 d[i][i] 判個負環
int d[N][N];
int main() {
IOS; cin >> n >> m; vector<pair<PII, int>> e(m);
rep (i, 1, n) rep (j, 1, n) d[i][j] = i == j ? 0 : inf;
for (auto &i : e) {
cin >> i.fi.fi >> i.fi.se >> i.se;
d[i.fi.fi][i.fi.se] = 1;
d[i.fi.se][i.fi.fi] = i.se ? -1 : 1;
}
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) umin(d[i][j], d[i][k] + d[k][j]);
int mx = -1, w;
rep (i, 1, n) {
if (d[i][i] < 0) { cout << "NO"; return 0; }
for (auto &j : e) if (d[i][j.fi.fi] == d[i][j.fi.se]) { cout << "NO"; return 0; }
rep (j, 1, n) if (d[i][j] > mx) mx = d[i][j], w = i;
}
cout << "YES\n" << mx << '\n';
rep (i, 1, n) cout << d[w][i] << ' ';
return 0;
}
F - The Struggling Contestant
先把-1考慮了, 無非是某個數多余 (n + 1) / 2
然后是將序列分段, 記錄每個數作為端點必須要出現的次數
比如 1 2 2 3 4 5, 對於2來說, a[2]於a[3]要隔開,並且這兩個數要作為切割后的序列的端點(前端和后端)
對於 1, 5, 本來就是端點, 直接+1, 最后就是端點之間的相互拼接, 不過拼接的兩個端點不能是相同的數,
你不能那端點 a[2] 和 a[3] 拼接, 但可以 a[2] 和 a[1]/a[6] 拼接, 既然都是端點了, 肯定貪心的先和其他端點拼接
最后如果存在 沒有拼接的端點, 紀要使用那些單點了,
es 1 2 2 2 2 3 4, a[2] a[1] a[3] a[6] a[7] a[4] a[5] a[6]
當前剩下端點 a[4] 和 a[5], 只好使用 a[6] 去分割了 2 1 2 4 2 3 2
答案也就是 k + max(0, \(max_f[x]\) - k - 2), f[i] 表示 i 作為端點的數量, k是相鄰端點的數量
簡單來說 k, 是必須要所示的貢獻, 兩個相鄰的相同的數, 拆入一個數, 最少貢獻 +1, 1 2 2 -> 2 1 2 貢獻為1
然后是相互插入 2 2 2 3 3 -> 2 3 2 3 2, 沒貢獻, 2 2 2 2 3 3 4 -> 2 3 2 3 2 4 2, 額外使用了單點 a[7], 貢獻+1
1 2 2 2 3 3 4 4 4 5 -> 1 2 3 4 2 3 4 2 4 5, 無額外貢獻, 說白了就是看那個最多的數作為端點其他數能不能將這個完全分割
為啥是 max(0, \(max_f[x]\) - k - 2) 要減個2? 你把那個最多的點作為整個序列的前后端點, 不挨着其他數
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n; VI a(n + 1), cnt(n + 1), f(n + 1); k = 0;
rep (i, 1, n) {
cin >> a[i]; ++cnt[a[i]];
if (i > 1 && a[i] == a[i - 1]) f[a[i]] += 2, ++k;
}
if (*max_element(all(cnt)) > (n + 1) / 2) { cout << "-1\n"; continue; }
++f[a[1]], ++f[a[n]];
cout << k + max(0, *max_element(all(f)) - k - 2) << '\n';
}
return 0;
}