The 2nd Universal Cup. Stage 11: Nanjing【杂题】
A. Cool, It’s Yesterday Four Times More
容易证明如下结论:同一连通块内袋鼠的输赢情况相同。枚举连通块暴力就行了。时间复杂度
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e3 + 5;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
bool Mbe;
int n, m, vis[N][N];
char a[N][N];
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i] + 1;
for (int j = 1; j <= m; j++) vis[i][j] = 0;
}
auto chk = [&](int x, int y) {
return x >= 1 && x <= n && y >= 1 && y <= m && a[x][y] == '.';
};
auto bfs = [&](int sx, int sy) {
vector <pi> res;
queue <pi> q;
q.push(make_pair(sx, sy));
vis[sx][sy] = 1;
while (!q.empty()) {
auto it = q.front();
int x = it.fi;
int y = it.se;
q.pop();
res.emplace_back(x - sx, y - sy);
for (int k = 0; k < 4; k++) {
int nx = x + dx[k];
int ny = y + dy[k];
if (chk(nx, ny) && !vis[nx][ny]) {
vis[nx][ny] = 1;
q.push(make_pair(nx, ny));
}
}
}
// cout << "-------\n";
// cout << "sx = " << sx << ", sy = " << sy << "\n";
// for (auto [x, y] : res) cout << x << " " << y << "\n";
return res;
};
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == '.' && !vis[i][j]) {
auto tmp = bfs(i, j);
bool ok = true;
for (int x = 1; x <= n; x++)
for (int y = 1; y <= m; y++) {
if (x == i && y == j) continue;
bool flag = false;
for (auto [dx, dy] : tmp)
if (!chk(x + dx, y + dy)) {
flag = true;
break;
}
if (!flag) {
ok = false;
goto end;
}
}
end :
if (ok) ans += tmp.size();
}
cout << ans << "\n";
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
4
2 5
.OO..
O..O.
1 3
O.O
1 3
.O.
2 3
OOO
OOO
*/
C. Primitive Root
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e5 + 5;
bool Mbe;
LL p, m;
void solve() {
cin >> p >> m;
LL ans = 0;
auto cnt = [&](LL x) {
return x / p + (x % p >= 1);
};
auto calc = [&](LL l, LL r) {
return cnt(r) - cnt(l - 1);
};
LL x = p - 1;
LL curm = 0, curx = 0;
for (int i = 60; i >= 0; i--) {
if (x & (1LL << i)) curx += 1LL << i;
if (m & (1LL << i)) {
LL cur = curm ^ curx;
ans += calc(cur, cur + (1LL << i) - 1);
curm += 1LL << i;
}
}
if ((curm ^ x) % p == 1 && curm <= m) ans += 1;
cout << ans << "\n";
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
3
2 0
7 11
1145141 998244353
*/
D. Red Black Tree
设
一种做法是直接维护差分数组。另一种做法可以考虑做一些简单优化,首先每次可以启发式合并并且只需要枚举到最浅子树大小,然后一整条链可以一起转移,需要求端点单调的区间
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e6 + 5, inf = 1e9;
bool Mbe;
int n, a[N], fa[N], sum[N], dep[N], len[N], ed[N], ns[N];
char s[N];
vector <int> e[N];
vector <int> f[N];
void chkmn(int &x, int y) {
x = min(x, y);
}
void dfs(int u, int ff) {
sum[u] = sum[ff] + a[u];
dep[u] = dep[ff] + 1;
len[u] = n + 1;
for (auto v : e[u]) {
dfs(v, u);
chkmn(len[u], len[v]);
}
if (len[u] == n + 1) len[u] = 0;
len[u] += 1;
ed[u] = u;
if (e[u].size() == 1) {
ed[u] = ed[e[u][0]];
}
}
void calc(int u) {
if (!e[u].size()) {
if (a[u]) {
f[u].emplace_back(1);
f[u].emplace_back(0);
} else {
f[u].emplace_back(0);
f[u].emplace_back(1);
}
ns[u] = 0;
return;
}
for (auto v : e[u]) calc(v);
if (e[u].size() >= 2) {
int son = e[u][0];
swap(f[u], f[son]);
f[u].resize(len[u]);
for (auto v : e[u]) {
if (v == son) continue;
for (int i = 0; i < len[u]; i++) {
f[u][i] += f[v][i];
}
}
f[u].emplace_back(inf);
static int tmp[N];
if (a[u]) {
for (int i = 0; i <= len[u]; i++) {
tmp[i] = f[u][i] + 1;
if (i) chkmn(tmp[i], f[u][i - 1]);
}
} else {
for (int i = 0; i <= len[u]; i++) {
tmp[i] = f[u][i];
if (i) chkmn(tmp[i], f[u][i - 1] + 1);
}
}
ns[u] = inf;
for (int i = 0; i <= len[u]; i++) {
f[u][i] = tmp[i];
chkmn(ns[u], f[u][i]);
}
} else if (e[u].size() == 1 && (e[fa[u]].size() >= 2 || u == 1)) {
int v = ed[u];
if (f[v].size() != len[v] + 1) while (1);
static int g[N][2], t[2];
auto upd = [&](int &x) {
x = max(x, 0);
x = min(x, len[v]);
};
auto qry = [&](int k, int l, int r) {
if (l > len[v] || r < 0) return inf;
upd(l);
upd(r);
assert(l <= r);
int res = 0;
int p = t[k];
if (r < p) {
res = g[r][k];
} else if (l <= p && r >= p) {
res = g[p][k];
} else {
assert(l > p);
res = g[l][k];
}
return res;
};
for (int i = 0; i <= len[v]; i++) {
g[i][0] = f[v][i] + i;
g[i][1] = f[v][i] - i;
}
for (int k = 0; k < 2; k++) {
t[k] = 0;
for (int i = 0; i <= len[v]; i++) {
if (g[t[k]][k] > g[i][k]) t[k] = i;
}
}
int cnt = dep[v] - dep[u];
int d = sum[fa[v]] - sum[fa[u]];
f[u].resize(len[u] + 1);
for (int i = 0; i <= len[u]; i++) {
int v0 = qry(0, i - d, i) + d - i;
int v1 = qry(1, i - cnt, i - d) + i - d;
f[u][i] = min(v0, v1);
}
ns[u] = inf;
for (int i = 0; i <= len[u]; i++) {
chkmn(ns[u], f[u][i]);
}
assert(ns[u] == ns[v]);
int tmp = v;
while (true) {
ns[tmp] = ns[v];
tmp = fa[tmp];
if (tmp == u) break;
}
}
}
void solve() {
cin >> n;
cin >> s + 1;
for (int i = 1; i <= n; i++) {
a[i] = s[i] - '0';
}
for (int i = 2; i <= n; i++) {
cin >> fa[i];
e[fa[i]].emplace_back(i);
}
dfs(1, 0);
calc(1);
for (int i = 1; i <= n; i++) {
cout << ns[i] << " \n"[i == n];
}
for (int i = 1; i <= n; i++) {
e[i].clear();
f[i].clear();
sum[i] = dep[i] = len[i] = ed[i] = ns[i] = 0;
}
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
2
9
101011110
1 1 3 3 3 6 2 2
4
1011
1 1 3
*/
E. Extending Distance
转成对偶图上的最小割。将原图中的边费用设为
原图的边权很大,而
时间复杂度为
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 5e3 + 5, M = 5e5 + 5, inf = 2e9 + 1234;
constexpr LL inff = 1e18;
bool Mbe;
struct E {
int to, flow, cost, nxt;
void clr() {
to = flow = cost = nxt = 0;
}
} e[M];
int tot = 1, hd[N];
void add_edge(int u, int v, int w, int c) {
e[++tot] = { v, w, c, hd[u] }, hd[u] = tot;
}
void add(int u, int v, int w, int c = 0) {
add_edge(u, v, w, c);
add_edge(v, u, 0, -c);
}
int n, m, k, s, t, c[N][N], d[N][N];
int id(int x, int y) {
return (x - 1) * (m - 1) + y;
}
int dep[N], cur[N];
bool bfs() {
memset(dep, -1, sizeof(dep));
dep[s] = 0;
cur[s] = hd[s];
queue <int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = hd[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (dep[v] != -1 || e[i].flow == 0) continue;
dep[v] = dep[u] + 1;
cur[v] = hd[v];
if (v == t) return true;
q.push(v);
}
}
return false;
}
LL dfs(int u, LL flow) {
if (u == t) return flow;
LL res = 0;
for (int i = cur[u]; i; i = e[i].nxt) {
if (!flow) break;
cur[u] = i;
int v = e[i].to;
if (dep[v] != dep[u] + 1 || !e[i].flow) continue;
LL x = dfs(v, min(1LL * e[i].flow, flow));
e[i].flow -= x;
e[i ^ 1].flow += x;
flow -= x;
res += x;
}
return res;
}
int dis[N], pre[N], val[N], eid[N]; bool vis[N];
bool spfa() {
queue <int> q;
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
q.push(s);
val[s] = inf;
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = hd[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (e[i].flow && dis[v] > dis[u] + e[i].cost) {
dis[v] = dis[u] + e[i].cost;
val[v] = min(val[u], e[i].flow);
pre[v] = u;
eid[v] = i;
if (!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
return dis[t] != dis[0];
}
LL mcmf(int k) {
LL res = 0;
while (k) {
spfa();
val[t] = min(val[t], k);
k -= val[t];
res += 1LL * val[t] * dis[t];
int x = t;
while (x != s) {
e[eid[x]].flow -= val[t];
e[eid[x] ^ 1].flow += val[t];
x = pre[x];
}
}
return res;
}
void solve() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
for (int j = 1; j < m; j++) {
int x;
cin >> x;
c[i][j] = x;
add(id(i, j), id(i + 1, j), x);
add(id(i + 1, j), id(i, j), x);
}
for (int i = 2; i <= n; i++)
for (int j = 0; j < m; j++) {
int x;
cin >> x;
d[i][j] = x;
if (j == 0 || j == m - 1) continue;
add(id(i, j), id(i, j + 1), x);
add(id(i, j + 1), id(i, j), x);
}
int L = tot + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j < m; j++) {
add(id(i, j), id(i + 1, j), 0, 1);
add(id(i + 1, j), id(i, j), 0, 1);
}
for (int i = 2; i <= n; i++)
for (int j = 0; j < m; j++) {
if (j == 0 || j == m - 1) continue;
add(id(i, j), id(i, j + 1), 0, 1);
add(id(i, j + 1), id(i, j), 0, 1);
}
int R = tot;
s = id(n + 1, m - 1) + 1;
t = s + 1;
for (int i = 1; i < m; i++) {
add(s, id(1, i), inf);
}
for (int i = 1; i < m; i++) {
add(id(n + 1, i), t, inf);
}
LL flow = 0;
while (bfs()) flow += dfs(s, inff);
for (int i = L; i <= R; i += 2) e[i].flow += k;
LL res = mcmf(k);
cout << res << "\n";
for (int i = 1; i <= n; i++) {
for (int j = 1; j < m; j++) {
cout << c[i][j] + (k - e[L].flow) + (k - e[L + 2].flow) << " ";
L += 4;
}
cout << "\n";
}
for (int i = 2; i <= n; i++) {
for (int j = 0; j < m; j++) {
if (j == 0 || j == m - 1) {
cout << d[i][j] << " ";
continue;
}
cout << d[i][j] + (k - e[L].flow) + (k - e[L + 2].flow) << " ";
L += 4;
}
cout << "\n";
}
for (int i = 2; i <= tot; i++) e[i].clr();
tot = 1;
fill(hd + 1, hd + t + 1, 0);
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
2
3 4 6
2 1 15
7 1 9
13 3 2
3 6 1 2
5 2 15 3
3 3 3
1 1
2 2
3 3
1 1 1
2 2 2
*/
F. Equivalent Rewriting
建有向图
直接跑拓扑排序,如果某个时刻队列中有不少于
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e6 + 5;
bool Mbe;
int n, m, ns[N], d[N];
vector <int> buc[N], e[N];
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int k;
cin >> k;
for (int j = 1; j <= k; j++) {
int x;
cin >> x;
buc[x].emplace_back(i);
}
}
for (int i = 1; i <= m; i++) {
if (buc[i].size() <= 1) continue;
int p = buc[i].back();
for (auto x : buc[i]) {
if (x == p) break;
e[x].emplace_back(p);
d[p]++;
}
}
queue <int> q;
for (int i = 1; i <= n; i++) {
if (d[i] == 0) q.push(i);
}
bool ok = false;
int x = -1, y = -1;
auto chk = [&]() {
if (q.size() > 1) {
x = q.front();
q.pop();
y = q.front();
q.pop();
ok = true;
}
return ok;
};
while (!q.empty()) {
if (chk() == true) break;
int u = q.front();
q.pop();
for (auto v : e[u]) {
if (--d[v] == 0) q.push(v);
}
}
if (ok) {
// cout << x << " " << y << "\n";
iota(ns + 1, ns + n + 1, 1);
if (x > y) swap(x, y);
for (int i = y; i >= x + 1; i--) ns[i] = ns[i - 1];
ns[x] = y;
cout << "Yes\n";
for (int i = 1; i <= n; i++) cout << ns[i] << " ";
cout << "\n";
} else {
cout << "No\n";
}
for (int i = 1; i <= n; i++) {
d[i] = 0;
e[i].clear();
}
for (int i = 1; i <= m; i++) buc[i].clear();
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
3
3 6
3 3 1 5
2 5 3
2 2 6
2 3
3 1 3 2
2 3 1
1 3
2 2 1
*/
G. Knapsack
考虑如果已经确定了最终选了哪些物品,显然把其中费用最大的
因此如果我们将所有物品按照
时间复杂度
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 5e3 + 5, M = 1e4 + 5;
bool Mbe;
int n, m, k, v[N], c[N]; pi d[N];
LL f[N][M], ans;
void solve() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> d[i].fi >> d[i].se;
}
sort(d + 1, d + n + 1);
for (int i = 1; i <= n; i++) {
v[i] = d[i].fi, c[i] = d[i].se;
// cout << v[i] << " " << c[i] << "\n";
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
f[i][j] = f[i - 1][j];
if (j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + c[i]);
}
priority_queue <int> q;
LL cur = 0;
auto upd = [&](int x) {
if (q.size() < k) {
q.push(-x);
cur += x;
} else if (-q.top() < x) {
cur -= -q.top();
q.pop();
q.push(-x);
cur += x;
}
};
if (k == 0) {
cout << f[n][m] << "\n";
return;
}
for (int i = n; i >= 0; i--) {
LL val = f[i][m];
// cout << val << " " << cur << "\n";
ans = max(ans, cur + val);
upd(c[i]);
}
cout << ans << "\n";
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; t = 1;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
10 50 1
12 516184197
25 89514235
30 521894533
31 388523197
31 480227821
35 28242326
36 114173760
38 163268500
42 971377551
44 182173741
*/
I. Counter
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e6 + 5;
bool Mbe;
int n, m;
pi c[N];
void solve() {
cin >> n >> m;
bool ok = true;
for (int i = 1; i <= m; i++) {
cin >> c[i].fi >> c[i].se;
}
sort(c + 1, c + m + 1);
for (int i = 1; i <= m; i++)
if (c[i - 1].fi != c[i].fi) {
if (c[i].se - c[i - 1].se != c[i].fi - c[i - 1].fi) {
ok &= c[i].fi - c[i - 1].fi >= c[i].se + (c[i - 1].se > 0);
}
} else {
ok &= c[i].se == c[i - 1].se;
}
if (ok) cout << "Yes\n";
else cout << "No\n";
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
3
7 4
4 0
2 2
7 1
5 1
3 2
2 2
3 1
3 1
3 100
*/
J. Suffix Structure
首先有一个暴力
接下来的一步非常厉害。考虑对于一个点
如果是第一种情况,
可以维护一个
总时间复杂度
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long LL;
typedef unsigned long long ull;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 4e5 + 5;
const ull base = 1e9 + 7;
bool Mbe;
ull pw[N], ths[N], ahs[N];
int val[N], dlt[N];
int n, m, fa[N], c[N], a[N], ans[N], dep[N];
int nxt[N], nxv[N], anc[N][30];
unordered_map <ull, int> id;
struct info {
int fail;
map <int, int> ch;
} T[N];
vector <int> vec;
queue <int> q;
void build() {
for (auto p : T[0].ch) {
int i = p.fi, u = p.se;
T[u].fail = 0, dep[u] = 1, q.push(u);
ths[u] = i;
}
while (!q.empty()) {
int u = q.front(); q.pop();
vec.push_back(u);
for (auto p : T[u].ch) {
int i = p.fi, v = p.se;
dep[v] = dep[u] + 1, q.push(v);
ths[v] = ths[u] * base + (ull)(i);
int w = T[u].fail;
while (w && !T[w].ch.count(i)) w = T[w].fail;
if (T[w].ch.count(i)) T[v].fail = T[w].ch[i];
}
}
for (int i = 1; i <= n; i++) id[ths[i]] = i;
}
void calc(int u) {
int l = 0, r = m, res = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (id.count(ths[u] * pw[mid] + ahs[mid])) res = mid, l = mid + 1;
else r = mid - 1;
}
nxt[u] = res;
nxv[u] = id[ths[u] * pw[res] + ahs[res]];
}
int climb(int u, int k) {
for (int i = 0; i <= 20; i++)
if (k >> i & 1) u = anc[u][i];
return u;
}
void add0(int l, int r, int v) {
ans[l] += v, ans[l + 1] -= v, ans[r + 1] -= v, ans[r + 2] += v;
}
void add1(int l, int r, int v, int d) {
add0(l, r, v * d);
ans[l] += d, ans[r + 1] -= d, ans[r + 1] -= r * d, ans[r + 2] += r * d;
}
void add_dlt(int l, int r, int v) {
dlt[l] -= v, dlt[r + 1] += v;
}
void calc_ans() {
val[0] = 0;
for (int i = 1; i <= n; i++) val[i] = 1;
for (int j = n - 1; j >= 0; j--) {
int i = vec[j];
int t = nxt[i], u = nxv[i];
if (dep[T[u].fail] >= t) {
int f = climb(T[u].fail, t);
val[f] += val[i];
add0(1, t, val[i] * (dep[i] - dep[f]));
} else {
int f = 0;
val[f] += val[i];
add_dlt(1, t, val[i]);
add1(1, t, dep[i], val[i]);
}
}
dlt[1] += val[0];
for (int i = 1; i <= m; i++) dlt[i] += dlt[i - 1];
for (int i = 1; i <= m; i++) ans[i] += ans[i - 1];
for (int i = 1; i <= m; i++) ans[i] += ans[i - 1];
int u = 0;
for (int j = 1; j <= m; j++) {
while (u && !T[u].ch.count(a[j])) u = T[u].fail;
if (T[u].ch.count(a[j])) {
u = T[u].ch[a[j]];
ans[j] += dep[u] * dlt[j];
}
}
}
void solve() {
cin >> n >> m;
pw[0] = 1;
for (int i = 1; i <= n; i++) pw[i] = pw[i - 1] * base;
for (int i = 1; i <= n; i++) cin >> fa[i], anc[i][0] = fa[i];
for (int i = 1; i <= n; i++) {
cin >> c[i];
T[fa[i]].ch[c[i]] = i;
}
for (int i = 1; i <= m; i++) cin >> a[i];
for (int i = 1; i <= m; i++) ahs[i] = ahs[i - 1] * base + (ull)(a[i]);
build();
for (int i = 1; i <= n; i++) calc(i);
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= n; i++) anc[i][j] = anc[anc[i][j - 1]][j - 1];
calc_ans();
for (int i = 1; i <= m; i++) cout << ans[i] << " \n"[i == m];
n = m = max(n, m) + 10;
for (int i = 0; i <= n; i++) T[i].fail = dep[i] = 0, T[i].ch.clear();
for (int i = 0; i <= m; i++) ans[i] = dlt[i] = 0;
vec.clear();
id.clear();
}
bool Med;
signed main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
2
11 3
0 1 2 0 4 5 4 6 0 9 10
1 3 2 2 1 3 4 1 3 2 1
3 2 4
5 16
0 0 0 1 4
1 2 3 2 2
2 1 3 3 2 1 3 2 1 3 2 2 1 1 2 1
*/
K. Grand Finale
注意到如果手牌上限为
具体来说,记 Q
,且没有爆过牌。这里因为抽到的牌的集合是已知的,且抽牌的数量也是已知的,我们能够简单计算出手牌中有多少张 Q
。记 B
,最少需要多少个 Q
才能抽完牌堆。这里利用了手牌上限的单调性。
转移都很简单。计算答案则为枚举 Q
的数量是否支持我们抽完牌堆。如果可以,就可以计算出当前手牌个数,更新答案。时间复杂度
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 2.5e3 + 5, inf = 1e9;
bool Mbe;
int n, m;
char a[N], b[N];
bool dp[N][2 * N];
int f[N][2 * N], cq[N], cb[N], ct[N];
void chkmn(int &x, int y) {
x = min(x, y);
}
void solve() {
cin >> n >> m;
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n + i; j++) {
dp[i][j] = false;
}
cin >> a + 1 >> b + 1;
int sq = 0;
int sb = 0;
for (int i = 1; i <= n; i++) {
sq += a[i] == 'Q';
sb += a[i] == 'B';
}
int st = n - sq - sb;
for (int i = 1; i <= m; i++) {
cq[i] = cq[i - 1] + (b[i] == 'Q');
cb[i] = cb[i - 1] + (b[i] == 'B');
ct[i] = ct[i - 1] + (b[i] == 'W');
}
for (int i = 0; i <= sb + cb[m]; i++) {
f[m][i] = f[m + 1][i] = 0;
}
for (int i = m - 1; i >= 0; i--)
for (int j = 0; j <= sb + cb[i]; j++) {
f[i][j] = max(0, f[i + 1][j + (b[i + 1] == 'B')] - (b[i + 1] == 'Q')) + 1;
if (j) chkmn(f[i][j], max(0, f[i + 2][j - 1 + (b[i + 1] == 'B')] - (b[i + 1] == 'Q')));
}
dp[0][sq] = true;
int ans = inf;
for (int i = 0; i <= m - 1; i++)
for (int j = 0; j <= n + i; j++)
if (dp[i][j]) {
int cnb = sb + cb[i] - (i - (sq + cq[i] - j)) / 2;
int cnt = j + cnb + st + ct[i];
if (f[i][cnb] <= j) {
chkmn(ans, cnt);
}
if (j) {
if (i == m - 1) chkmn(ans, cnt);
else dp[i + 1][j - 1 + (b[i + 1] == 'Q')] = true;
}
if (cnb) {
if (i == m - 1 || i == m - 2) chkmn(ans, cnt);
else dp[i + 2][j + (b[i + 1] == 'Q') + (b[i + 2] == 'Q')] = true;
}
}
if (ans == inf) cout << "IMPOSSIBLE\n";
else cout << ans << "\n";
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
2
2 6
BG
BQWBWW
4 6
GQBW
WWWWQB
*/
L. Elevator
直接贪心,把所有物品按照
来自官方题解的证明
我们通过说明该贪心策略产生的答案达到了下界来说明最优性。为了求出答案的下界,我们将所有重量为
给一个序列
,将序列中的所有数分成若干组,每组最多包含 个数。一个分组方案的得分是所有组最大值的和,求最小得分。
由于原问题中的任何一个配送方案都能对应新问题中的一个配送方案,因此新问题的答案不比原问题大,也就是说新问题的答案就是原问题答案的下界。显然新问题可以贪心解决,答案就是所有下标对
- 情况一:前面总重量为
的货物恰好能装满一趟电梯。此时原问题和新问题消耗了相同的电能。
- 情况二:出现电梯容量只剩
,但是下一个包裹的重量却是 的情况。
由于
实现有一些细节。时间复杂度
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e5 + 5;
bool Mbe;
LL n, k, ans;
struct item {
LL c, w, v;
bool operator < (const item &p) const {
return v > p.v;
}
} a[N];
void solve() {
cin >> n >> k;
ans = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i].c >> a[i].w >> a[i].v;
}
sort(a + 1, a + n + 1);
int pos = 1;
for (int i = 1, j; i <= n; i = j) {
if (!a[i].c) {
j = i + 1;
continue;
}
LL kk = k;
j = i;
while (j <= n && kk >= a[j].w * a[j].c) kk -= a[j].w * a[j].c, a[j].c = 0, j++;
if (j == i) {
LL t = kk / a[i].w;
LL cc = a[i].c / t;
ans += a[i].v * cc;
a[i].c -= cc * t;
} else {
ans += a[i].v;
if (j <= n) {
LL t = kk / a[j].w;
kk -= t * a[j].w;
a[j].c -= t;
if (kk) {
while (pos <= n && (pos < j || !a[pos].c || a[pos].w == 2)) pos++;
a[pos].c--;
}
}
}
}
cout << ans << "\n";
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
2
4 6
1 1 8
7 2 5
1 1 7
3 2 6
8 1200000
100000 1 100000
100000 1 12345
100000 2 100000
100000 2 12345
100000 1 100000
100000 1 12345
100000 2 100000
100000 2 12345
*/
M. Trapping Rain Water
考虑序列全局最大值的位置。左边的部分贡献是前缀
考虑如何维护修改。以前缀
总时间复杂度
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pi;
#define fi first
#define se second
constexpr int N = 1e6 + 5;
#define m ((l + r) >> 1)
#define lc x << 1
#define rc lc | 1
bool Mbe;
LL n, a[N], pre[N], suf[N];
struct SGT1 {
LL mx[N << 2];
void build(int x, int l, int r) {
if (l == r) {
mx[x] = a[l];
return;
}
build(lc, l, m);
build(rc, m + 1, r);
mx[x] = max(mx[lc], mx[rc]);
}
void upd(int x, int l, int r, int p, LL v) {
if (l == r) {
mx[x] = v;
return;
}
if (p <= m) upd(lc, l, m, p, v);
else upd(rc, m + 1, r, p, v);
mx[x] = max(mx[lc], mx[rc]);
}
int qryL(int x, int l, int r, int ql, int qr, LL v) {
if (mx[x] <= v) return 0;
if (l == r) return l;
if (qr > m) {
int res = qryL(rc, m + 1, r, ql, qr, v);
if (res) return res;
}
if (ql <= m) return qryL(lc, l, m, ql, qr, v);
return 0;
}
int qryR(int x, int l, int r, int ql, int qr, LL v) {
if (mx[x] <= v) return 0;
if (l == r) return l;
if (ql <= m) {
int res = qryR(lc, l, m, ql, qr, v);
if (res) return res;
}
if (qr > m) return qryR(rc, m + 1, r, ql, qr, v);
return 0;
}
} sgt;
struct SGT2 {
LL sum[N << 2], tag[N << 2], len[N << 2];
void push_up(int x) {
sum[x] = sum[lc] + sum[rc];
}
void push_tag(int x, LL v) {
tag[x] = v;
sum[x] = len[x] * v;
}
void push_down(int x) {
if (tag[x]) {
push_tag(lc, tag[x]);
push_tag(rc, tag[x]);
tag[x] = 0;
}
}
void build(int x, int l, int r, LL* val) {
sum[x] = tag[x] = 0;
len[x] = r - l + 1;
if (l == r) {
sum[x] = val[l];
return;
}
build(lc, l, m, val);
build(rc, m + 1, r, val);
push_up(x);
}
void cov(int x, int l, int r, int ql, int qr, LL v) {
if (ql <= l && qr >= r) {
push_tag(x, v);
return;
}
push_down(x);
if (ql <= m) cov(lc, l, m, ql, qr, v);
if (qr > m) cov(rc, m + 1, r, ql, qr, v);
push_up(x);
}
LL qry(int x, int l, int r, int ql, int qr) {
if (ql <= l && qr >= r) {
return sum[x];
}
push_down(x);
LL res = 0;
if (ql <= m) res += qry(lc, l, m, ql, qr);
if (qr > m) res += qry(rc, m + 1, r, ql, qr);
return res;
}
} tp, ts;
#undef m
void solve() {
cin >> n;
int pos = 0;
LL sum = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (a[i] > a[pos]) pos = i;
sum += a[i];
}
pre[0] = suf[n + 1] = 0;
for (int i = 1; i <= n; i++) {
pre[i] = max(pre[i - 1], a[i]);
}
for (int i = n; i >= 1; i--) {
suf[i] = max(suf[i + 1], a[i]);
}
sgt.build(1, 1, n);
tp.build(1, 1, n, pre);
ts.build(1, 1, n, suf);
int m;
cin >> m;
while (m--) {
int x, y;
cin >> x >> y;
a[x] += y;
if (a[x] > a[pos]) pos = x;
sum += y;
sgt.upd(1, 1, n, x, a[x]);
int nl = x == 1 ? 0 : sgt.qryL(1, 1, n, 1, x - 1, a[x]);
int nr = x == n ? 0 : sgt.qryR(1, 1, n, x + 1, n, a[x]);
if (!nr) nr = n + 1;
if (!nl) {
tp.cov(1, 1, n, x, nr - 1, a[x]);
}
if (nr == n + 1) {
ts.cov(1, 1, n, nl + 1, x, a[x]);
}
LL cur = 0;
cur += ts.qry(1, 1, n, pos, n);
// cout << cur << " !1\n";
if (pos > 1) cur += tp.qry(1, 1, n, 1, pos - 1);
// cout << cur << " !2\n";
cout << cur - sum << "\n";
}
}
bool Med;
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) solve();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
return 0;
}
/*
2
6
1 2 3 4 5 6
2
1 2
3 3
5
100 10 1 10 100
1
3 100
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效