Solution of “The 2024 ICPC North America Championship”, and it also be kown as “The 3rd Universal Cup. Stage 0: Trial Contest”.
D
给定一个长度为
注意到最多翻转一次, 且等价于将原序列逆序.
于是定位
时间复杂度
def check ():
for pos in range(n):
if a[pos] == b[0]:
for i in range(m):
if (a[(pos + i) % n] != b[i]): return False
break
return True
if __name__ == "__main__":
n, m = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
if check(): print('1')
else:
a.reverse()
if check(): print('1')
else: print('0')
A
有
设
转移考虑第
时间复杂度
#include <bits/stdc++.h>
const int N = 52, M = 1e5 + 5;
int n, a[N], b[N], suma, sumb;
int main () {
std::cin >> n;
for (int i = 1; i <= n; i++)
std::cin >> a[i] >> b[i],
suma += a[i], sumb += b[i];
std::vector<std::vector<int>> f(n + 1, std::vector<int>(suma + 1, N * M));
f[0][suma] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= suma; j++) {
f[i][j] = f[i - 1][j];
if (j <= suma - a[i])
f[i][j] = std::min(f[i][j], f[i - 1][j + a[i]] + b[i]);
}
int ans = N * M;
for (int j = 0; j <= suma; j++)
ans = std::min(ans, std::max(j, f[n][j]));
std::cout << ans << "\n";
return 0;
}
J
有
注意到若答案为
时间复杂度
if __name__ == "__main__":
n, p = map(int, input().split())
a = [int(input()) for _ in range(n)]
sum = 0
for i in range(n):
if p <= (i + 1) * (a[i] - 1) + sum:
print(i); exit(0)
sum += a[i]
print(n)
G
存在
现在你要从
设
注意到所有格子的决策都是独立的, 于是考虑求
- 若
, 则一定选择走 的方向, 有 . - 若
, 有 .- 若当前指向
, 则走 , 概率为 , 贡献为 . - 若到
的计时器大于 , 则走 , 概率为 , 贡献为 . - 若到
的计时器不大于 , 则走 , 概率为 , 贡献为 .
- 若当前指向
特别的, 若
时间复杂度
n, m, p = map(int, input().split())
f = [[0] * (m + 1) for _ in range(n + 1)]
for i in range(n, 0, -1):
for j in range(m, 0, -1):
if i == n and j == m: continue
if i == n: f[i][j] = f[i][j + 1] + p / 4
elif j == m: f[i][j] = f[i + 1][j] + p / 4
else:
a, b = min(f[i + 1][j], f[i][j + 1]), max(f[i + 1][j], f[i][j + 1])
if b >= a + p: f[i][j] = a + p / 4
else: f[i][j] = a / 2 + ((p - b + a) * b) / (2 * p) + ((b - a) * (a + b)) / (4 * p)
print(f[1][1])
H
如图所示, 每座山都是三角形, 用其顶点坐标代替.
有
注意到线条长度等于
时间复杂度
#include <bits/stdc++.h>
class SegmentTree {
private:
class Node {
public:
Node *lc, *rc;
int min, cnt, lazy;
Node (int l, int r) : lc(nullptr), rc(nullptr), min(0), cnt(r - l + 1), lazy(0) {}
} *root = nullptr;
int limL, limR;
void pushdown (Node *p, int L, int R) {
if (p->lazy == 0) return;
int mid = L + R >> 1;
if (p->lc == nullptr) p->lc = new Node(L, mid);
p->lc->min += p->lazy, p->lc->lazy += p->lazy;
if (p->rc == nullptr) p->rc = new Node(mid + 1, R);
p->rc->min += p->lazy, p->rc->lazy += p->lazy;
p->lazy = 0;
}
std::pair<int, int> merge (std::pair<int, int> a, std::pair<int, int> b) {
int min = std::min(a.first, b.first), cnt = 0;
if (a.first == min) cnt += a.second;
if (b.first == min) cnt += b.second;
return std::make_pair(min, cnt);
}
void upd (int l, int r, int k, Node *&p, int L, int R) {
if (p == nullptr) p = new Node(L, R);
if (l <= L and R <= r) { p->min += k, p->lazy += k; return; }
pushdown(p, L, R);
int mid = L + R >> 1;
if (l <= mid) upd(l, r, k, p->lc, L, mid);
if (r >= mid + 1) upd(l, r, k, p->rc, mid + 1, R);
if (p->lc == nullptr and p->rc == nullptr) std::tie(p->min, p->cnt) = std::make_pair(0, R - L + 1);
else if (p->lc == nullptr) std::tie(p->min, p->cnt) = std::make_pair(0, mid - L + 1 + p->rc->cnt * (p->rc->min == 0));
else if (p->rc == nullptr) std::tie(p->min, p->cnt) = std::make_pair(0, R - mid + p->lc->cnt * (p->lc->min == 0));
else std::tie(p->min, p->cnt) = merge(std::make_pair(p->lc->min, p->lc->cnt), std::make_pair(p->rc->min, p->rc->cnt));
}
std::pair<int, int> qry (int l, int r, Node *p, int L, int R) {
if (p == nullptr) return std::make_pair(0, std::min(r, R) - std::max(l, L) + 1);
if (l <= L and R <= r) return std::make_pair(p->min, p->cnt);
pushdown(p, L, R);
int mid = L + R >> 1;
auto res = std::make_pair(INT_MAX, 0);
if (l <= mid) res = merge(res, qry(l, r, p->lc, L, mid));
if (r >= mid + 1) res = merge(res, qry(l, r, p->rc, mid + 1, R));
return res;
}
public:
SegmentTree (int l, int r) : limL(l), limR(r), root(nullptr) {}
void upd (int l, int r, int k) {
upd(l, r, k, root, limL, limR);
}
std::pair<int, int> qry (int l, int r) {
return qry(l, r, root, limL, limR);
}
};
int q, w, x, y;
std::set<std::pair<int, int>> S;
int main () {
std::cin >> q >> w;
SegmentTree tree(0, w - 1);
while (q--) {
std::cin >> x >> y;
if (S.find(std::make_pair(x, y)) != S.end())
tree.upd(std::max(0, x - y), std::min(x + y - 1, w - 1), -1),
S.erase(std::make_pair(x, y));
else
tree.upd(std::max(0, x - y), std::min(x + y - 1, w - 1), 1),
S.insert(std::make_pair(x, y));
auto ans = tree.qry(0, w - 1);
std::cout << std::fixed << std::setprecision(6) << sqrt(2) * (w - ans.second * (ans.first == 0)) << "\n";
}
return 0;
}
I
给定长度为 ?
改成 N
/A
/C
之一, 使最终的字符串中恰好存在 NAC
作为子序列.
设 A
的贡献, 前缀中 N
的数量为 C
的数量为 NAC
作为子序列. 转移时枚举变成什么即可, 可以用 bitset
优化. 时间复杂度
#include <bits/stdc++.h>
const int N = 50;
int n, k;
char s[N], ans[N];
std::bitset<2600> f[N][N][N];
int main() {
scanf("%d%d%s", &n, &k, s + 1);
for (int i = 0; i <= n; i++) f[0][0][i][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= i; j++)
for (int k = 0; k <= n - i + 1; k++) {
if ((s[i] == 'N' or s[i] == '?') and j >= 1)
f[i][j][k] |= f[i - 1][j - 1][k];
if (s[i] == 'A' or s[i] == '?')
f[i][j][k] |= (f[i - 1][j][k] << (j * k));
if ((s[i] == 'C' or s[i] == '?') and k + 1 <= n)
f[i][j][k] |= f[i - 1][j][k + 1];
if ((s[i] != 'N' and s[i] != 'A' and s[i] != 'C') or s[i] == '?')
f[i][j][k] |= f[i - 1][j][k];
}
for (int i = 0; i <= n; i++) {
if (f[n][i][0][k]) {
int p = i, q = 0, r = k;
for (int i = n; i >= 1; i--) {
if ((s[i] == 'N' or s[i] == '?') and p >= 1 and f[i - 1][p - 1][q][r])
ans[i] = 'N', p--;
else if ((s[i] == 'A' or s[i] == '?') and r - p * q >= 0 and f[i - 1][p][q][r - p * q])
ans[i] = 'A', r -= p * q;
else if ((s[i] == 'C' or s[i] == '?') and q + 1 <= n and f[i - 1][p][q + 1][r])
ans[i] = 'C', q++;
else if (s[i] == '?') ans[i] = 'B';
else ans[i] = s[i];
}
ans[n + 1] = 0;
printf("%s\n", ans + 1);
return 0;
}
}
puts("-1");
return 0;
}
M
存在 a++
或 b++
. 问最多能解决多少个任务.
一个自然的想法是设 a++
和 b++
. 转移时枚举每个任务, 枚举每个值为
注意到一个二元组
对于每个二元组, 它最多加入
#include <bits/stdc++.h>
const int N = 5e3 + 5;
int n, a, b, ans;
bool f[N][N];
std::set<int> S[N];
std::vector<std::pair<int, int>> upd;
int main () {
std::cin >> n >> a >> b;
f[0][0] = true, S[0].insert(0);
for (int al, ar, bl, br, p = 1; p <= n; p++) {
std::cin >> al >> ar >> bl >> br;
upd.clear();
for (int i = std::max(0, al - a); i <= std::min(p, ar - a); i++) {
auto l = S[i].lower_bound(std::max(0, bl - b));
if (l != S[i].end()) {
auto r = S[i].upper_bound(std::min(p, br - b));
for (auto it = l; it != r; it++) {
if (not f[i + 1][*it])
f[i + 1][*it] = true,
upd.push_back(std::make_pair(i + 1, *it));
if (not f[i][(*it) + 1])
f[i][(*it) + 1] = 1,
upd.push_back(std::make_pair(i, (*it) + 1));
}
S[i].erase(l, r);
}
}
for (auto x : upd)
S[x.first].insert(x.second),
ans = std::max(ans, x.first + x.second);
}
std::cout << ans << "\n";
return 0;
}
v1.3.10