10.21训练赛
A. P1084 [NOIP2012 提高组] 疫情控制
二分答案,倍增+贪心来check。
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define endl cout << '\n'
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
using pll = pair<ll, ll>;
using pdd = pair<ld, ld>;
const ll N = 5e4 + 1, M = 16;
ll n, m, k, c, ans;
ll fa[N][M], no[N], dep[N], a[N], d2[N];
ll dis[N][M], d[N], qr, qf;
pll q[N];
vector<pll> g[N];
inline void bfs() {
queue<ll> q;
q.emplace(1), dep[1] = 1;
while (q.size()) {
ll t = q.front();
q.pop();
if (dep[t] == 2)
d2[++c] = t, no[t] = t;
for (auto [v, w] : g[t])
if (!dep[v]) {
dep[v] = dep[t] + 1, d[v] = d[t] + w;
fa[v][0] = t, dis[v][0] = w;
if (dep[v] > 2)
no[v] = no[t];
q.emplace(v);
}
}
fu(i, 1, M - 1) fu(j, 2, n) {
ll k = fa[j][i - 1];
fa[j][i] = fa[k][i - 1];
dis[j][i] = dis[j][i - 1] + dis[k][i - 1];
}
}
inline bool bfs(ll x, bool v[]) {
queue<ll> q;
q.emplace(x);
while (q.size()) {
ll t = q.front();
q.pop();
bool f = 0;
for (auto [s, w] : g[t])
if (dep[s] > dep[t]) {
f = 1;
if (!v[s])
q.emplace(s);
}
if (!f)
return 0;
}
return 1;
}
inline bool ck(ll x) {
ll cnt[n + 1]{};
qr = qf = 0;
bool vis[n + 1]{};
fu(i, 1, m) {
ll t = 0, u = a[i], v = no[u];
fd(j, M - 1, 0) if (t + dis[u][j] <= x) {
t += dis[u][j];
u = fa[u][j];
if (u <= 1)
break;
}
if (u <= 1)
q[qr++] = {x - t, v};
else
vis[u] = 1;
}
ll p = 1, u;
while (qf ^ qr) {
auto [w, v] = q[qf++];
while (u = d2[p])
if (vis[u] || cnt[u] || bfs(u, vis))
++p;
else
break;
if (!u)
return 1;
if (d[u] <= w || u == v)
++p;
else
++cnt[v];
}
fu(i, p, c) {
u = d2[i];
if (!vis[u] && !cnt[u] && !bfs(u, vis))
return 0;
}
return 1;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
#ifndef ONLINE_JUDGE
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
cin >> n;
ll u, v, w;
fu(i, 2, n) {
cin >> u >> v >> w;
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
bfs();
sort(d2 + 1, d2 + c + 1, [](ll &a, ll &b) { return d[a] < d[b]; });
cin >> m;
fu(i, 1, m) cin >> a[i];
sort(a + 1, a + m + 1, [](ll &a, ll &b) { return d[a] > d[b]; });
ll l = -1, r = 1e15;
while (l < r - 1) {
ll m = l + r >> 1;
ck(m) ? r = m : l = m;
}
cout << (r < 1e15 ? r : -1);
}
B. P1083 [NOIP2012 提高组] 借教室
二分答案,差分+前缀和check。
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define endl cout << '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
using pll = pair<ll, ll>;
using pdd = pair<ld, ld>;
const ll N = 1e6 + 5, M = 1e6 + 7;
ll n, m, k, ans;
ll a[N], b[N], s[N], t[N];
inline bool ck(ll x) {
ll p[n + 2]{};
fu(i, 1, x) p[s[i]] += b[i], p[t[i] + 1] -= b[i];
fu(i, 1, n) {
p[i] += p[i - 1];
if (p[i] > a[i])
return 0;
}
return 1;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
fu(i, 1, n) cin >> a[i];
fu(i, 1, m) cin >> b[i] >> s[i] >> t[i];
ll l = 0, r = m + 1;
while (l < r - 1) {
ll m = l + r >> 1;
if (ck(m))
l = m;
else
r = m;
}
if (r <= m)
cout << "-1\n"
<< r;
else
cout << 0;
}
C. P1080 [NOIP2012 提高组] 国王游戏
把相邻两个人的两种先后情况的答案表示出来并尝试最小化他们对答案的贡献,
可以发现需要前者手上金币乘积小于后者,需要高精度。
n = int(input())
a, b = map(int, input().split())
ans = 0
c = []
for i in range(n):
l, r = map(int, input().split())
c.append([l, r])
c.sort(key = lambda x : x[0] * x[1])
for i in c:
ans = max(ans, a // i[1])
a *= i[0]
print(ans)
D. P7872 「Wdoi-4」觉姐姐和恋妹妹
参考P1004进行dp,思考觉能将路径上负权值丢弃的边界。
这题数据不够强,看别人ac记录有些可以被hack。
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
const ll N = 310;
ll n, m, k, ans;
ll a, b, c, d;
ll X, Y;
ll f[N][N], x[N][N], dp[2 * N][N][N];
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
memset(f, 200, sizeof f);
memset(dp, 200, sizeof dp);
fu(i, 1, n) fu(j, 1, m) cin >> x[i][j];
cin >> a >> b >> c >> d;
f[c][d + 1] = f[c + 1][d] = 0;
fd(i, c, 1) fd(j, d, 1) f[i][j] = max(f[i + 1][j], f[i][j + 1]) + x[i][j];
ans = f[1][1];
dp[1][1][1] = 0;
X = min(a, c), Y = min(b, d);
fu(i, 1, X) fu(j, 1, Y) fu(k, max(i + j - Y, 1ll), X) {
ll l = i + j - k;
if (!l)
break;
mx(dp[i][j][k], max({dp[i - 1][j][k - 1], dp[i - 1][j][k],
dp[i][j - 1][k], dp[i][j - 1][k - 1]}));
dp[i][j][k] += max(0ll, x[i][j]);
if (i ^ k) {
dp[i][j][k] += x[k][l];
} else {
if (i < a)
mx(ans, dp[i][j][i] + f[i][j + 1]);
if (j < b)
mx(ans, dp[i][j][i] + f[i + 1][j]);
mx(ans, max(dp[i - 1][j][i], dp[i][j - 1][i - 1]) + f[i][j]);
}
}
cout << ans;
}
E. P6154 游走
由于选择所有路径的概率相等,记忆化搜索得到路径的总数和总长即可。
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
typedef long long ll;
const ll N = 1e5 + 1, M = 998244353;
ll t, n, m, k;
ll a, b, c, d, ans;
ll cnt[N], len[N];
vector<ll> g[N];
string s;
inline ll inv(ll x) {
return x ^ 1 ? (M - M / x) * inv(M % x) % M : 1;
}
inline void dfs(ll x) {
if (~cnt[x])
return;
cnt[x] = 1, len[x] = 0;
for (ll v : g[x]) {
dfs(v);
cnt[x] += cnt[v];
len[x] += len[v] + cnt[v];
}
cnt[x] %= M, len[x] %= M;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
memset(cnt + 1, -1, n << 3);
memset(len + 1, -1, n << 3);
fu(i, 1, m) {
cin >> a >> b;
g[a].emplace_back(b);
}
fu(i, 1, n) dfs(i), c = (c + cnt[i]) % M, d = (d + len[i]) % M;
cout << d * inv(c) % M;
}
F. P1110 [ZJOI2007]报表统计
stl,使用emplcace_hint略快于emplace,参考https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
#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;
using pii = pair<int, int>;
const int N = 1e6;
int n, m, a, k, c[N], x[N];
int msg = N;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
set<pair<pii, int>> s;
multiset<int> s0, s1;
cin >> n >> m;
decltype(s.begin()) it[n + 1];
fu(i, 1, n) {
cin >> x[i], s1.emplace(x[i]);
it[i] = s.emplace_hint(s.end(), pii{i, 0}, x[i]);
}
fu(i, 2, n) s0.emplace(abs(x[i] - x[i - 1]));
sort(x + 1, x + n + 1);
fu(i, 2, n) mn(msg, x[i] - x[i - 1]);
string op;
fu(i, 1, m) {
cin >> op;
if (op[0] == 'I') {
cin >> a >> k;
auto j = s.emplace_hint(it[a + 1], pii{a, ++c[a]}, k), i = j++;
--i;
if (j != s.end()) {
s0.erase(s0.find(abs(j->second - i->second)));
s0.emplace(abs(j->second - k));
}
s0.emplace(abs(i->second - k));
auto j1 = s1.emplace(k), i1 = j1++;
if (j1 != s1.end())
mn(msg, *j1 - k);
if (i1 != s1.begin())
mn(msg, k - *--i1);
} else if (op[4] == 'S') {
cout << msg << '\n';
} else {
cout << *s0.begin() << '\n';
}
}
}
G. P3806 【模板】点分治1
模板题。
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef long double ld;
const ll N = 1e5 + 10, M = 998244353;
ll t, n, m, k, ans;
ll a[N], b[N], c, d[N];
ll q[N], sz[N], mx[N]{N}, rt;
bool f[N], vis[N];
vector<pll> g[N];
void get_rt(ll u, ll f, ll tot) {
sz[u] = 1, mx[u] = 0;
for (auto [v, w] : g[u])
if (v ^ f && !vis[v]) {
get_rt(v, u, tot);
sz[u] += sz[v];
mx(mx[u], sz[v]);
}
mx(mx[u], tot - sz[u]);
if (mx[u] < mx[rt])
rt = u;
}
void get_dis(ll u, ll f, ll dis, ll fa) {
a[++c] = u, b[u] = fa, d[u] = dis;
for (auto [v, w] : g[u])
if (v ^ f && !vis[v])
get_dis(v, u, dis + w, fa);
}
void calc(ll u) {
a[c = 1] = u; // 可到达的点
b[u] = u; // 属于哪颗子树
d[u] = 0; // 距离
for (auto [v, w] : g[u])
if (!vis[v])
get_dis(v, u, w, v);
sort(a + 1, a + c + 1, [](ll &x, ll &y) { return d[x] < d[y]; });
fu(i, 1, m) if (!f[i]) {
ll l = 1, r = c;
while (l < r && !f[i]) {
if (d[a[l]] + d[a[r]] > q[i])
--r;
else if (d[a[l]] + d[a[r]] < q[i])
++l;
else if (b[a[l]] ^ b[a[r]])
f[i] = 1;
else
d[a[r]] ^ d[a[r - 1]] ? ++l : --r;
}
}
}
void cal(ll u) {
vis[u] = 1;
calc(u);
for (auto [v, w] : g[u])
if (!vis[v])
rt = 0, get_rt(v, 0, sz[v]), cal(rt);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
ll u, v, w;
cin >> n >> m;
fu(i, 2, n) {
cin >> u >> v >> w;
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
fu(i, 1, m) cin >> q[i];
get_rt(1, 0, n), cal(rt);
fu(i, 1, m) cout << (f[i] ? "AYE" : "NAY") << '\n';
}
H. P2471 [SCOI2007]降雨量
rmq,注意细节。
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
using ll = long long;
const ll N = 1e5, M = 20;
ll n, m, a, b, c, d, st[N][M], x[N], y[N], lg[N]{-1};
bool f[N][M];
unordered_map<ll, ll> mp;
inline ll qry(ll a, ll b) {
ll j = lg[b - a + 1], r = b - (1 << j) + 1;
return max(st[a][j], st[r][j]);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
fu(i, 1, n) cin >> x[i] >> y[i], st[i][0] = y[i], mp[x[i]] = i;
fu(j, 1, M - 1) fu(i, 1, n) {
ll k = 1 << j;
if (i + k - 1 > n)
break;
k >>= 1;
st[i][j] = max(st[i][j - 1], st[i + k][j - 1]);
f[i][j] = f[i][j - 1] & f[i + k][j - 1];
}
fu(i, 1, n) lg[i] = lg[i / 2] + 1;
cin >> m;
fu(i, 1, m) {
cin >> c >> d;
ll l = upper_bound(x + 1, x + n + 1, c) - x;
ll r = lower_bound(x + 1, x + n + 1, d) - x - 1;
a = mp[c], b = mp[d];
bool f = d - c == b - a;
if (r < l) {
if (a && b)
cout << (y[b] <= y[a] ? (d - c == 1 ? "true" : "maybe") : "false");
else
cout << "maybe";
} else {
ll mx = qry(l, r);
if (b) {
if (mx >= y[b])
cout << "false";
else if (a)
cout << (y[b] <= y[a] ? (f ? "true" : "maybe") : "false");
else
cout << "maybe";
} else {
cout << (a && y[a] <= mx ? "false" : "maybe");
}
}
cout << '\n';
}
}