11.25训练赛
A.P1144 最短路计数
bfs,从样例中可以看出重边算不同路径,注意取模。
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define dbg(x) cout << #x << '=' << x << ' '
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
const ll N = 1e7, M = 100003;
ll t, n, m, k, ans;
ll c[N], d[N], q[N], qf, qb;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
vector<ll> g[n + 1];
ll u, v;
fu(i, 1, m) {
cin >> u >> v;
if (u ^ v) {
g[u].emplace_back(v);
g[v].emplace_back(u);
}
}
q[qb++] = c[1] = d[1] = 1;
while (qf ^ qb) {
u = q[qf++], c[u] %= M;
for (ll v : g[u]) {
if (!d[v])
d[v] = d[u] + 1, q[qb++] = v;
if (d[u] + 1 == d[v])
c[v] += c[u];
}
}
fu(i, 1, n) cout << c[i] << '\n';
}
B.P1106 删数问题
相当于取n-k个数字,从左到右贪心,输出要去掉前导0。
n, k = input(), int(input())
m = len(n) - 1
ans, num = '', m - k
p, i, mx = -1, 0, ':'
while i < m:
if(n[i] < mx):
p, mx = i, n[i]
if m - i == num:
num -= 1
ans += n[p]
i, mx = p, ':'
i += 1
print(int(ans))
C.CF1612E Messages
假设固定了\(x\)条信息,则某条信息的期望为\(\frac{\sum min(x, k_i)}{x}\),
这里\(i = 1, 2, 3...\)代表第\(i\)个被期望阅读该信息的人的\(k\)值,
\(∵k_i <= 20∴x <= 20\)时取到最大值,枚举\(x\)对信息按期望排序即可。
import io
import os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
N = 200001
n = int(input())
m, k = [0] * n, [0] * n
a = set()
for i in range(n):
m[i], k[i] = map(int, input().split())
a.add(m[i])
u, d = 0, 1
for x in range(1, 21):
s = [0] * N
for i in range(n):
s[m[i]] += min(x, k[i])
a = sorted(a, key=lambda i: s[i], reverse=1)
S = sum(s[i] for i in a[:x])
if S * d > u * x:
u, d = S, x
ans = a[:x]
print(len(ans))
for i in ans:
print(i, end=' ')
D.CF1612F Armor and Weapons
设\(dp[i][j]\)表示第\(i\)步\(armor_j\)可以配对的最大\(weapon\),转移显然,
重点是观察到数值的增长类似斐波那契数列,达到上限后无法增长,即复杂度
\(O(n * (\log n + n / m))\),所以在\(n > m\)时交换\(armor\)与\(weapon\)保证复杂度。
import io
import os
from queue import *
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
n, m = map(int, input().split())
f = 0
if n > m:
n, m, f = m, n, 1
mp, q = {}, int(input())
for _ in range(q):
a, w = map(int, input().split())
if f:
a, w = w, a
if a in mp:
mp[a].add(w)
else:
mp[a] = set([w])
f = [0] * (n + 1)
f[1], t = 1, 0
while f[n] < m:
g = f[:]
for i in range(1, n + 1):
if f[i]:
p = f[i] + i + (i in mp and f[i] in mp[i])
g[min(p, n)] = max(g[min(p, n)], f[i])
g[i] = max(g[i], min(p, m))
t += 1
f = g
print(t)
E.P7815 自傷無色
对于当前根节点不同子树下距离为\(a, b\)的点(\(a \ge b\)),有\(a - b < x < a + b\),
对数量的贡献是\(2b - 1\),对大小的贡献为\((2a + b)(2b - 1)\),通过dsu on tree
或者线段树合并解决。
#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define dbg(x) cout << #x << '=' << x << ' '
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using LL = __int128;
using pll = pair<ll, ll>;
const ll N = 1e5 + 10, M = 1e9 + 7, i2 = M + 1 >> 1;
ll t, n, u, v, w, p, c, val, num;
ll W[N], d[N], sz[N], son[N], T[3][N], s[3];
gp_hash_table<ll, ll> mp;
vector<pll> g[N];
ll inv(ll x) { return x ^ 1 ? -M / x * inv(M % x) % M : 1; }
void upd(ll p, ll x, ll f) {
while (p <= n) {
T[0][p] += f, T[1][p] += (2 * x - 1) * f;
T[2][p] += x * (2 * x - 1) % M * f;
p += p & -p; // 分别维护前缀个数,2x - 1, x * (2x - 1)
}
}
void qry(ll p, ll f) {
while (p) {
fu(i, 0, 2) s[i] += T[i][p] * f;
p -= p & -p;
}
}
void dfs0(ll u, ll f) {
sz[u] = 1, W[u] = d[u];
for (auto [v, w] : g[u])
if (v ^ f) {
d[v] = d[u] + w, dfs0(v, u), sz[u] += sz[v];
if (sz[v] > sz[son[u]])
son[u] = v;
}
}
void cal(ll u, ll f, ll F, ll w) {
p = mp[d[u]], t = (d[u] - w) % M;
if (F) {
upd(p, d[u] % M, F);
} else {
// 计算距离小于等于当前节点的节点的贡献
s[0] = s[1] = s[2] = 0, qry(p, 1), s[1] %= M, s[2] %= M;
c = (s[1] - s[0] * 2 * w) % M, num += c;
// b(2b - 1),b = d[x] - w 代回去推
val += s[2] + w * ((2 * w - 1) * s[0] % M - 2 * s[1]);
// 2a(2b - 1), a = d[u] - w
val = (val + 2 * t * c) % M;
// 计算比当前节点距离大的节点的贡献
s[0] = s[1] = 0, qry(p, -1), qry(n, 1), s[1] %= M;
c = 2 * t - 1, num += c * s[0], val += t * c % M * s[0];
val = (val + (s[1] + s[0] * (1 - 2 * w)) % M * c) % M;
}
for (auto [v, x] : g[u])
if (v ^ f)
cal(v, u, F, w);
}
void dfs(ll u, ll f, ll F = 0) {
for (auto [v, w] : g[u])
if (v ^ f && v ^ son[u])
dfs(v, u, 1); // 处理轻儿子,消除影响
if (son[u]) // 处理重儿子,不消除影响
dfs(son[u], u, 0), upd(mp[d[son[u]]], d[son[u]] % M, 1);
for (auto [v, w] : g[u])
if (v ^ f && v ^ son[u])
// 先计算贡献再更新,计算时去掉根节点距离
cal(v, u, 0, d[u] % M), cal(v, u, 1, 0);
if (F) // 清空影响
for (auto [v, w] : g[u])
if (v ^ f)
cal(v, u, -1, 0);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
fu(i, 2, n) {
cin >> u >> v >> w;
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
dfs0(1, 0), sort(W + 1, W + n + 1); // 标记重儿子
c = unique(W + 1, W + n + 1) - W - 1; // 把距离离散化
fu(i, 1, c) mp[W[i]] = i;
dfs(1, 0), num = (num % M + M) % M;
cout << (num ? (val * inv(num) % M + M) % M : 0);
}
F.P7814 心の記憶
简单构造。
#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
typedef long long ll;
typedef long double ld;
const ll N = 100, M = 1e9 + 7, inv2 = M + 1 >> 1;
ll t, n, m, k, ans;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> t;
while (t--) {
string s;
cin >> n >> m >> s;
if (n == m || n == 1 || n == 2 && s[0] ^ s[1])
cout << "-1\n";
else {
bool f = 0;
fu(i, 1, n - 1) if (s[i] == s[0]) {
s.insert(i, m - n, s[i] == '1' ? '0' : '1');
f = 1;
break;
}
if (!f)
s.insert(2, m - n, s[2] == '1' ? '0' : '1');
cout << s << '\n';
}
}
}
G.P6833 雷雨
观察样例可以发现目标是三源最短路的交点。
#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
using namespace std;
typedef long long ll;
const int N = 1000;
int n, m, a, b, c, e[N][N];
short int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
ll d[3][N][N], ans = 1e18;
struct node {
short int x, y;
ll d;
bool operator<(node x) const { return d > x.d; }
};
void dfs(int i, int j, int k) {
priority_queue<node> q;
q.push({i, j, e[i][j]});
d[k][i][j] = e[i][j];
while (!q.empty()) {
node no = q.top();
int i = no.x, j = no.y;
ll dis = no.d;
q.pop();
fu(l, 0, 3) {
int x = i + dx[l], y = j + dy[l];
if (x >= 0 && x <= n - 1 && y >= 0 && y <= m - 1 &&
dis + e[x][y] < d[k][x][y]) {
d[k][x][y] = dis + e[x][y];
q.push({x, y, dis + e[x][y]});
}
}
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m >> a >> b >> c;
fu(i, 0, n - 1) fu(j, 0, m - 1) cin >> e[i][j];
memset(d, 0x3f, sizeof d), dfs(0, a - 1, 0);
dfs(m - 1, b - 1, 1), dfs(m - 1, c - 1, 2);
fu(i, 0, n - 1) fu(j, 0, m - 1) {
ll tmp = 0;
fu(k, 0, 2) tmp += d[k][i][j];
tmp -= 2 * e[i][j];
ans = min(ans, tmp);
}
cout << ans;
return 0;
}