3.24训练赛
A.CF1657D For Gamers. By Gamers.
推一下式子发现要求是\(C/c*dh > DH\),所以先处理每个单位价格对应最大\(dh\),
再更新每多买一个单位时的贡献,复杂度\(nlogn\)
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define sz(x) ll(x.size())
#define all(x) x.begin(), x.end()
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using LL = __int128;
using pll = pair<ll, ll>;
constexpr ll N = 1e6 + 1;
ll t, n, m, k;
ll c, d, h, a[N], b[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
fu(i, 1, n) {
cin >> c >> d >> h;
mx(a[c], d * h);
}
fu(i, 1, m) fu(j, 1, m / i) mx(b[j * i], j * a[i]);
fu(i, 2, m) mx(b[i], b[i - 1]);
cin >> k;
fu(i, 1, k) {
cin >> d >> h;
int p = upper_bound(b + 1, b + m + 1, d * h) - b;
cout << (p > m ? -1 : p) << ' ';
}
}
B.CF1657E Star MST
由最小生成树的定义有\(w(u, v) \geq max(\ w(1, u),\ w(1,v)\ )\),令\(f[i][j]\)
代表考虑\(i\)个点的完全图,与\(1\)相连的边最大值为\(j\)的方案数,转移时枚举有多少条
与\(1\)相连的边被设置为\(j\)
#include <bits/extc++.h>
#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)
#define all(x) x.begin(), x.end()
#define sz(x) int(x.size())
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using LL = __int128;
using ll = long long;
using ld = long double;
using pll = pair<ll, ll>;
constexpr int N = 3e2 + 10, M = 998244353;
ll t, n, m, k, a, b;
ll f[N][N], c[N][N]{1};
inline ll qpow(ll a, ll b) {
ll r = 1;
for (; b; b >>= 1, a = a * a % M)
if (b & 1)
r = r * a % M;
return r;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> k;
fu(i, 1, n) {
c[i][0] = 1;
fu(j, 1, n - 1) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % M;
}
f[1][0] = 1;
fu(i, 1, n) fu(j, 1, k) {
fu(l, 0, i - 1) {
t = (l - 1) * l / 2 + l * (i - 1 - l);
f[i][j] += c[i - 1][l] * f[i - l][j - 1] % M * qpow(k - j + 1, t) % M;
}
f[i][j] %= M;
}
cout << f[n][k];
}
C.CF1657F Words on Tree
分析一下限制,每个点最多有两个选择,再加两个点对应一个单词正反读,2-sat解决。
#include <bits/extc++.h>
#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)
#define all(x) x.begin(), x.end()
#define sz(x) int(x.size())
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
constexpr int N = 4e5 + 1, M = 1.6e6 + 1;
int n, m, u, v, d[N], p[N], fa[N];
int c, sc, no, st[M], sn[M], dfn[M], low[M];
char w[N * 2];
string s;
vector<int> g[N], G[M];
void dfs(int u = 1) {
for (int v : g[u])
if (v ^ fa[u])
d[v] = d[u] + 1, fa[v] = u, dfs(v);
}
void ins(int u, int v, int no, string s) {
int len = sz(s), l = 0, r = len - 1;
while (l <= r)
if (d[u] > d[v])
p[l++] = u, u = fa[u];
else
p[r--] = v, v = fa[v];
fu(i, 0, len - 1) {
int x = p[i];
if (!w[x])
w[x] = s[i], w[x + n] = s[len - 1 - i];
int l[]{x, x + n}, r[]{no, no + m}, c[]{s[i], s[len - 1 - i]};
fu(i, 0, 1) fu(j, 0, 1) if (w[l[i]] ^ c[j]) {
G[l[i]].emplace_back(r[!j]);
G[r[j]].emplace_back(l[!i]);
}
}
}
void tarjan(int x) {
dfn[x] = low[x] = ++no, st[c++] = x;
for (int y : G[x])
if (!dfn[y])
tarjan(y), mn(low[x], low[y]);
else if (!sn[y])
mn(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++sc;
while (st[c] ^ x)
sn[st[--c]] = sc;
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
fu(i, 2, n) {
cin >> u >> v;
g[u].emplace_back(v), g[v].emplace_back(u);
}
dfs();
fu(i, 1, m) cin >> u >> v >> s, ins(u, v, 2 * n + i, s);
fu(i, 1, n + m << 1) dfn[i] ? void() : tarjan(i);
fu(i, 1, n) if (sn[i] == sn[i + n]) return puts("NO");
cout << "YES\n";
fu(i, 1, n) cout << (w[i] ? sn[i] < sn[i + n] ? w[i] : w[i + n] : 'a');
}
D.BZOJ4917 Hash Killer IV
反向模拟即可,核心是利用未改变的位进行还原,另外t += t << 3的操作也可以用逆元还原
(乘数与模数互质)。
#include <bits/extc++.h>
#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)
#define all(x) x.begin(), x.end()
#define sz(x) int(x.size())
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ui = unsigned int;
constexpr int N = 4e5 + 1, M = 8e5 + 2;
ui t, n;
void cal(ui &x, int l) {
auto y = x;
fu(i, 1, 31 / l) x ^= y >> i * l;
}
void cal(int l, ui &x) {
static bool y[32], f[32];
bitset<32> z(x);
fu(i, 0, 31) y[i] = z[i];
fu(i, l, 31) {
y[i] ^= y[i - l], z[i] = y[i];
f[i] = y[i] + y[i - l] + (i > l ? f[i - 1] : 0) > 1;
i < 31 ? y[i + 1] ^= f[i] : 0;
}
x = z.to_ullong();
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> t;
while (t--) {
cin >> n;
n -= n << 16, cal(n, 11);
cal(3, n), cal(n, 6), cal(10, n);
cout << n << '\n';
}
}
E.BZOJ3098 Hash Killer II
首先在此谢罪,没考虑到没人维护题目spj的情况,只好自己写了一个传题到洛谷
仅供参考。
考虑随机,\(base \geq 26\)时hash值不超过mod时是准确的,最大值%mod与
最大值/mod较小时冲突率也会降低,可以取\(l = 8\)
import random
from string import ascii_lowercase
n = 10 ** 5
print(n, 8)
for i in range(n // 10):
for c in random.sample(ascii_lowercase, 10):
print(c, end='')
F.CF1654C Alice and the Cake
贪心+模拟
#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 mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define sz(x) ll(x.size())
#define all(x) x.begin(), x.end()
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using LL = __int128;
using pll = pair<ll, ll>;
constexpr ll N = 1e6 + 1;
ll t, n, m, a, b, c, d, l, r, k;
ll x[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> t;
fu(_, 1, t) {
cin >> n, a = 0;
fu(i, 1, n) cin >> x[i], a += x[i];
sort(x + 1, x + n + 1, greater<ll>());
multiset<ll, greater<ll>> s;
s.emplace(a);
for (int i = 1; i <= n;) {
while (*s.begin() ^ x[i]) {
if (*s.begin() < x[i] || *s.begin() < 2) {
cout << "NO\n";
goto end;
}
a = *s.begin(), s.erase(s.begin());
s.emplace(a / 2), s.emplace(a / 2 + (a & 1));
}
s.erase(s.begin()), ++i;
}
cout << "YES\n";
end:;
}
}
G.CF1654D Potion Brewing Class
我们可以设一号药用量为\(1\),剩下的为\(\frac{a_i}{b_i}\),那么依题意一号药
原用量为\(\mathrm lcm \{b_i\}\),所以我们可以dfs维护分母质因数集合,
求出一号药用量后再dfs一遍求答案。
#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)
#define sz(x) int(x.size())
#define all(x) x.begin(), x.end()
#define f first
#define s second
using namespace std;
using ll = long long;
using pii = pair<int, int>;
constexpr int N = 2e5 + 1, M = 998244353;
int t, n, a, b, c, d, e, val[N], ans;
int qpow(int a, int b) {
int r = 1;
for (; b; b >>= 1, a = (ll)a * a % M)
b & 1 ? r = (ll)r * a % M : 0;
return r;
}
int exgcd(int a, int b, int &x, int &y) {
if (!b)
return x = 1, y = 0, a;
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int inv(int a) {
int x, y;
exgcd(a, M, x, y);
return x + (x < 0 ? M : 0);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> t;
fu(_, 1, t) {
cin >> n, ans = 0;
vector<pair<int, pii>> g[n + 1];
int cnt[n + 1]{}, mx[n + 1]{};
fu(i, 2, n) {
cin >> a >> b >> c >> d;
e = gcd(c, d), c /= e, d /= e;
g[a].emplace_back(b, pii{d, c});
g[b].emplace_back(a, pii{c, d});
}
auto upd = [&](int x, int f) {
fu(i, 2, sqrt(x)) while (!(x % i))
x /= i,
mx(mx[i], cnt[i] += f);
mx(mx[x], cnt[x] += f);
};
function<void(int, int)> dfs = [&](int u, int f) {
for (auto [v, F] : g[u])
if (v ^ f) {
upd(F.f, -1), upd(F.s, 1), dfs(v, u);
upd(F.s, -1), upd(F.f, 1);
}
};
dfs(1, 0), a = 1;
fu(i, 2, n) a = (ll)a * qpow(i, mx[i]) % M;
val[1] = a;
function<void(int, int)> dfs1 = [&](int u, int f) {
for (auto &[v, F] : g[u])
if (v ^ f) {
val[v] = (ll)val[u] * F.f % M * inv(F.s) % M;
dfs1(v, u);
}
};
dfs1(1, 0);
cout << accumulate(val + 1, val + n + 1, 0ll) % M << '\n';
}
}
H.BZOJ2618 [Cqoi2006]凸多边形
半平面交模板,这里用的暴力算法。
#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)
#define sz(x) int(x.size())
#define all(x) x.begin(), x.end()
#define x first
#define y second
using namespace std;
using ll = long long;
using db = double;
using pdd = pair<db, db>;
using poly = vector<pdd>;
constexpr db eps = 1e-10;
constexpr int N = 50;
int n, m;
db operator^(pdd a, pdd b) {
return a.x * b.y - a.y * b.x;
}
pdd operator-(pdd a, pdd b) {
return {a.x - b.x, a.y - b.y};
}
pdd operator+(pdd a, pdd b) {
return {a.x + b.x, a.y + b.y};
}
pdd operator*(pdd a, db x) {
return {a.x * x, a.y * x};
}
pdd operator/(pdd a, db x) {
return {a.x / x, a.y / x};
}
pdd inter(pdd s1, pdd e1, pdd s2, pdd e2) {
db d = e1 - s1 ^ e2 - s2;
db p = e1 - s2 ^ e2 - s2, q = e2 - s2 ^ s1 - s2;
return (s1 * p + e1 * q) / d;
}
poly cut(poly &p, pdd s, pdd e) {
poly r;
const int n = sz(p);
fu(i, 0, n - 1) {
int j = (i + 1) % n;
bool f0 = (s - p[i] ^ e - p[i]) > eps;
bool f1 = (s - p[j] ^ e - p[j]) > eps;
if (f0)
r.emplace_back(p[i]);
if (f0 ^ f1)
r.emplace_back(inter(p[i], p[j], s, e));
}
return r;
}
void cut(poly &p, const poly &q) {
int n = sz(q);
fu(i, 0, n - 1) p = cut(p, q[i], q[(i + 1) % n]);
}
db area(const poly &p) {
db r = 0;
int n = sz(p);
fu(i, 0, n - 1) r += p[i] ^ p[(i + 1) % n];
return r / 2;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m;
poly p(m), q;
fu(i, 0, m - 1) cin >> p[i].x >> p[i].y;
fu(i, 2, n) {
cin >> m, q.resize(m);
fu(j, 0, m - 1) cin >> q[j].x >> q[j].y;
cut(p, q);
}
cout << fixed << setprecision(3) << area(p);
}