Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)
Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)
A - Prison Break
int main() {
IOS;
for (cin >> _; _; --_) {
ll n, m; cin >> n >> m;
cout << (m - 1) * n + n << '\n';
}
return 0;
}
B - Restore Modulo
\(a_i - a_{i - 1}\) 注意到只有两种结果
- 当\(a_i - a_{i - 1} < 0\) 其值为 \(c - m\)
- 当\(a_i - a_{i - 1} \geqslant 0\) 其值为 \(c\)
当\(a_i - a_{i - 1}\) 值大于2个无解, 有两个值且不是一个大于等于0 小于0 无解
当\(a_i - a_{i - 1}\) 值有一个, m无限大
剩下的直接算出来\(c, m\) 再去特判 \(m \leqslant a_i\) 即可
ll a[N];
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> a[1]; set<ll> st; ll m, c;
rep(i, 2, n) cin >> a[i], st.insert(a[i] - a[i - 1]);
if (st.size() > 2) { cout << "-1\n"; continue; }
else if (st.size() == 2 && *st.rbegin() < 0) { cout << "-1\n"; continue; }
else if (st.size() == 2 && *st.begin() >= 0) { cout << "-1\n"; continue; }
else if (st.size() == 2) m = *st.rbegin() - *st.begin(), c = *st.rbegin();
else if (st.size() <= 1) { cout << "0\n"; continue; }
bool f = a[1] < m;
rep (i, 2, n) if (a[i] >= m || a[i] != (a[i - 1] + c) % m) f = 0;
if (f) cout << m << ' ' << c << '\n';
else cout << "-1\n";
}
return 0;
}
C - Basic Diplomacy
注意到每个数能用\(\left \lceil \frac{m}{2} \right \rceil\)
故在处理掉某天只能选一个人的情况(有解的情况下), 必定有解
int c[N], ans[N];
set<int> b[N];
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; bool f = 1;
rep(i, 1, n) c[i] = (m + 1) >> 1;
rep(i, 1, m) {
ans[i] = 0; clear(b[i]);
for (cin >> k; k; --k) cin >> cas, b[i].insert(cas);
if (b[i].size() == 1) ans[i] = *b[i].begin(), --c[*b[i].begin()];
}
rep(i, 1, m) if (!ans[i]) {
if (c[*b[i].begin()] > 0) --c[*b[i].begin()], ans[i] = *b[i].begin();
else --c[*b[i].rbegin()], ans[i] = *b[i].rbegin();
}
rep (i, 1, n) if (c[i] < 0) f = 0;
if (!f) { cout << "NO\n"; continue; }
cout << "YES\n"; rep(i, 1, m) cout << ans[i] << ' '; cout << '\n';
}
return 0;
}
D - Playlist
两个循环队列 a, b, a为原音乐的循环队列, b维护可能删除b[i]这首歌在原队列a中下一首歌的序列
循环检测b[i]是否能删除祁在原序列中的下一首歌
如果能, 就把a中的那首歌删除, 如果删除的歌也在b序列, 那再b序列中也删除
否则在b序列删除当前b[i]
对于每首歌, 要么b[i]的时候被删除, 或者b[i]本身被删除, 总的每首歌都被从b序列删除之后停止
故复杂度为 \(O(n)\)
struct node { int pre, nxt, k; } a[N], b[N];
int n, m, _, k, cas;
void delet(node* a, int id) {
a[a[id].nxt].pre = a[id].pre, a[a[id].pre].nxt = a[id].nxt;
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n; map<int, int> st; m = 0; VI ans;
rep(i, 1, n) {
cin >> a[i].k, b[i].pre = a[i].pre = i - 1;
b[i].k = i; b[i].nxt = a[i].nxt = i + 1;
}
b[1].pre = a[1].pre = n, b[n].nxt = a[n].nxt = 1;
for (int i = 1; ; i = b[i].nxt)
if (__gcd(a[b[i].k].k, a[a[b[i].k].nxt].k) == 1) {
int bnxt = b[i].nxt;
if (b[bnxt].k == a[b[i].k].nxt) delet(b, bnxt);
ans.pb(a[b[i].k].nxt); delet(a, a[b[i].k].nxt);
if (i == b[bnxt].k && b[bnxt].k == a[b[i].k].nxt) break;
}
else { delet(b, i); if (b[i].nxt == i) break; }
cout << ans.size() << ' ';
for (auto& i : ans) cout << i << ' '; cout << '\n';
}
return 0;
}
E Skyline Photo
一个单调栈即可, 因为要建筑要连续, 且只有在 b[i] 在当前序列中最低才有贡献
故维护一个单调栈, h[st.top()] > h[i] i可以和 st.top() 合并成一个序列, 且这段序列魅力值为 b[i]
为了dp, 我们还要再维护一个mx[i] 表示 不含 当前 i 这一序列的最大值, 则
f[i] = mx[i] + b[i]
对于 mx[i], 首先是 mx[i] = f[i - 1]
当 h[st.top()] > h[i] 时, i 可以合并, 则 mx[i] = max(mx[i], mx[st.top])
最后是在 h[st.top()] < h[i] 时, 还有一种选择, b[i] 没贡献 i, f[i] = max(f[i], f[st.top()])
const int N = 3e5 + 5;
int n, m, _, k, cas;
int h[N], b[N];
ll f[N], mx[N];
int main() {
IOS; cin >> n; stack<int> st;
rep(i, 1, n) cin >> h[i];
rep(i, 1, n) cin >> b[i];
rep(i, 1, n) {
for (mx[i] = f[i - 1]; !st.empty() && h[st.top()] > h[i]; st.pop())
umax(mx[i], mx[st.top()]);
f[i] = b[i] + mx[i];
if (!st.empty()) umax(f[i], f[st.top()]); st.push(i);
}
cout << f[n];
return 0;
}
F - Useful Edges
注意 5s 的时限
意味着\(O(n)\)跑了, 边和询问都是 \(n^2\) 的数量级, 也就是 \(O(n\times m + n \times q)\) 的复杂度是允许的
先弗洛伊德跑个最短路, 毕竟这是个求最短路的问题
对于每个询问 \((u, v, c)\), 好边是 \(d[u][x] + cost(x, y) + d[y][v] <= c\)
暴力的 \(O(m \times q)\) 是不行了, 只能想办法 \(O(n\times m + n \times q)\) 了
那就只能通过遍历 顶点 i, 来解决\((i, v, c)\)的询问了
对每个顶点预处理个 \(g[y] = max(c_k - d[y][v_k])\) 即枚举边的时候我们只用考虑 \(d[i][x] + cost(x, y)\)
即
memset(g, -1, sizeof g);
for (auto &[y, c] : h[i]) rep (j, 1, n) umax(g[j], c - d[j][y]);
rep (j, 1, m) if (d[i][e[j].u] + e[j].c <= g[e[j].v]) vis[j] = 1;
完整代码
struct node { int u, v, c; } e[N];
int n, m, _, k, cas;
vector<PII> h[M];
ll d[M][M], g[M];
bool vis[N];
int main() {
IOS; cin >> n >> m; memset(d, 0x3f, sizeof d);
rep (i, 1, n) d[i][i] = 0;
rep (i, 1, m) {
cin >> e[i].u >> e[i].v >> e[i].c;
umin(d[e[i].u][e[i].v], e[i].c); d[e[i].v][e[i].u] = d[e[i].u][e[i].v];
}
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) umin(d[i][j], d[i][k] + d[k][j]);
for (cin >> _; _; --_) { int u, v, c; cin >> u >> v >> c; h[u].pb(v, c); h[v].pb(u, c); }
rep (i, 1, n) {
memset(g, -1, sizeof g);
for (auto &[y, c] : h[i]) rep (j, 1, n) umax(g[j], c - d[j][y]);
rep (j, 1, m) if (d[i][e[j].u] + e[j].c <= g[e[j].v]) vis[j] = 1;
}
rep (i, 1, m) k += vis[i]; cout << k;
return 0;
}