26.10.7qbxt集训day7
T1

考虑必须要有个循环节,且循环节长度为 \(\gcd(n,k)\)。
多重组合数即可。
点击查看代码
#include <iostream>
#include <cmath>
#include <vector>
using std::cin;
using std::cout;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
int cnt[N];
int col[(int)1e7 + 10];
int b[N], x[N], y[N];
int inv[(int)1e7 + 10];
int fac[(int)1e7 + 10];
int ifac[(int)1e7 + 10];
std::vector<int> modi;
int gcd(int x, int y)
{
if (!x || !y)
return x | y;
int xx = __builtin_ctz(x);
int yy = __builtin_ctz(y);
int tmp;
int k = std::min(xx, yy);
y >>= yy;
while (x)
{
x >>= xx;
tmp = y - x;
xx = __builtin_ctz(tmp);
y = std::min(x, y);
x = abs(tmp);
}
return y << k;
}
void rd(int &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = (x << 3) + (x << 1) - '0' + c;
c = getchar();
}
x *= f;
}
void solve()
{
for (auto it : modi)
col[it] = 0;
modi.clear();
int n, k, c, q;
rd(n), rd(k), rd(c), rd(q);
for (int i = 1; i <= c; ++i)
rd(b[i]);
bool fl = true;
int len = gcd(n, k);
for (int i = 1; i <= c; ++i)
cnt[i] = 0;
for (int i = 1; i <= q; ++i)
{
int x, y;
rd(x), rd(y);
if (col[x % len] && col[x % len] != y)
fl = false;
if (!col[x % len])
cnt[y]++;
col[x % len] = y;
modi.push_back(x % len);
}
if (!fl)
{
cout << 0 << '\n';
return;
}
int ans = 1;
int all = len;
for (int i = 1; i <= c; ++i)
{
if (b[i] % (k / len))
{
cout << 0 << '\n';
return;
}
b[i] /= (k / len);
if (b[i] < cnt[i])
{
cout << 0 << '\n';
return;
}
b[i] -= cnt[i];
all -= cnt[i];
ans = 1ll * ans * ifac[b[i]] % mod;
}
cout << 1ll * ans * fac[all] % mod << '\n';
}
int main()
{
freopen("donut.in", "r", stdin);
freopen("donut.out", "w", stdout);
inv[1] = 1;
for (int i = 2; i <= 1e7; ++i)
inv[i] = 1ll * (-mod / i + mod) * inv[mod % i] % mod;
fac[0] = ifac[0] = 1;
for (int i = 1; i <= 1e7; ++i)
{
fac[i] = 1ll * fac[i - 1] * i % mod;
ifac[i] = 1ll * ifac[i - 1] * inv[i] % mod;
}
int t;
cin >> t;
while (t--)
solve();
return 0;
}
T2

注意到它让输出所有的长度,所以长度的总种类数并不多,直接暴力可过。
点击查看代码
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using std::cin;
using std::cout;
const int N = 110;
typedef long long ll;
bool vis[N];
int k[N];
int e[N][5];
std::queue<int> q;
//std::vector<int> cl;
std::map<ll, ll> ans;
std::map<ll, ll> cnt[N];
template<typename T>
void rd(T &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = (x << 3) + (x << 1) - '0' + c;
c = getchar();
}
x *= f;
}
int main()
{
freopen("baguette.in", "r", stdin);
freopen("baguette.out", "w", stdout);
ll n;
int m;
rd(n), rd(m);
for (int i = 1; i <= m; ++i)
{
rd(k[i]);
for (int j = 1; j <= k[i]; ++j)
{
int s;
rd(s);
e[i][j] = s;
}
}
if (n == 1)
{
cout << 1 << ' ' << 1 << '\n';
return 0;
}
cnt[1][n] = 1;
q.push(1);
vis[1] = true;
ans[n] = 1;
ll a;
int b;
while (q.size())
{
int x = q.front();
q.pop();
vis[x] = false;
for (auto it : cnt[x])
{
if (!it.second)
continue;
a = it.first / k[x];
b = it.first % k[x];
cnt[x][it.first] -= it.second;
if (b)
ans[a + 1] += it.second * b;
if (a == 0)
continue;
if (k[x] - b)
ans[a] += it.second * (k[x] - b);
for (int i = 1; i <= b; ++i)
{
cnt[e[x][i]][a + 1] += it.second;
if (!vis[e[x][i]])
{
vis[e[x][i]] = true;
q.push(e[x][i]);
}
}
if (a == 1)
continue;
for (int i = b + 1; i <= k[x]; ++i)
{
cnt[e[x][i]][a] += it.second;
if (!vis[e[x][i]])
{
vis[e[x][i]] = true;
q.push(e[x][i]);
}
}
}
// for (auto it : cnt[x])
// {
// if (!it.second)
// cl.push_back(it.first);
// }
// for (auto it : cl)
// cnt[x].erase(it);
// cl.clear();
}
for (auto it : ans)
cout << it.first << ' ' << it.second << '\n';
return 0;
}
T3

势能分析。
点击查看代码
#include <iostream>
#include <vector>
#include <unordered_map>
using std::cin;
using std::cout;
const int N = 1e5 + 10;
typedef long long ll;
struct Node
{
int mx;
int mx2;
int a;
ll ans;
int ap;
friend Node operator+(const Node &l, const Node &r)
{
Node ret;
ret.mx = std::max(l.mx, r.mx);
ret.mx2 = std::max(l.mx2, r.mx2);
ret.ans = l.ans + r.ans;
return ret;
}
} z[N << 2];
char opt[6];
int a[N];
int b[N];
int p[N];
int rep[N];
std::vector<int> modi;
#define root 1, n, 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
void build(int l, int r, int rt)
{
if (l == r)
{
z[rt].a = a[l];
z[rt].ap = a[p[l]];
z[rt].mx = a[l] - std::max(a[p[l]], 1);
z[rt].mx2 = a[l] - a[p[l]];
z[rt].ans = a[l] - a[l] % std::max(a[p[l]], 1);
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
void modify(int l, int r, int rt, int nowl, int nowr, int k)
{
if (k == 0)
{
if (z[rt].mx < 0)
return;
}
else
{
if (z[rt].mx2 - k < 0)
return;
}
if (l == r)
{
b[p[l]] = a[p[l]];
modi.push_back(l);
return;
}
int mid = (l + r) >> 1;
if (nowl <= mid)
modify(lson, nowl, nowr, k);
if (nowr > mid)
modify(rson, nowl, nowr, k);
}
void modicov(int l, int r, int rt, int p, int k, int opt)
{
if (l == r)
{
if (opt == 1)
z[rt].a = k;
else
z[rt].ap = k;
z[rt].mx = z[rt].a - std::max(z[rt].ap, 1);
z[rt].mx2 = z[rt].a - z[rt].ap;
z[rt].ans = z[rt].a - z[rt].a % std::max(z[rt].ap, 1);
return;
}
int mid = (l + r) >> 1;
if (p <= mid)
modicov(lson, p, k, opt);
else
modicov(rson, p, k, opt);
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
void rd(int &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = (x << 3) + (x << 1) - '0' + c;
c = getchar();
}
x *= f;
}
int main()
{
freopen("jam.in", "r", stdin);
freopen("jam.out", "w", stdout);
int n, q;
rd(n), rd(q);
for (int i = 1; i <= n; ++i)
rd(a[i]);
for (int i = 1; i <= n; ++i)
rd(p[i]), rep[p[i]] = i;
build(root);
for (int i = 1; i <= q; ++i)
{
cin >> opt;
if (opt[0] == 'S')
{
int u, v;
rd(u), rd(v);
std::swap(p[u], p[v]);
modicov(root, u, a[p[u]], 2);
modicov(root, v, a[p[v]], 2);
rep[p[u]] = u, rep[p[v]] = v;
}
else if (opt[0] == 'M')
{
int l, r, x;
rd(l), rd(r), rd(x);
modify(root, l, r, x);
for (auto it : modi)
{
a[it] %= std::max(b[p[it]] + x, 1);
modicov(root, rep[it], a[it], 2);
modicov(root, it, a[it], 1);
}
modi.clear();
}
cout << z[1].ans << '\n';
}
return 0;
}
T4

没听懂。
点击查看std
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2005;
const int M = 1005;
const ll NEG = -(1LL << 60);
int n, tot, num, now;
int fa[N], w[N], son[N][2], deg[N];
int le[N], ri[N], id[N], leaf[M];
int dis[N][M], ord[N][M], que[M];
ll f[N][M];
bool inside(int x, int p) {
return le[x] <= p && p <= ri[x];
}
void dfs(int x) {
le[x] = num + 1;
if (!deg[x]) {
id[x] = ++num;
leaf[num] = x;
} else {
dfs(son[x][0]);
dfs(son[x][1]);
}
ri[x] = num;
}
void getdis(int x, int pre, int p, int d) {
dis[x][p] = d;
if (fa[x] && fa[x] != pre)
getdis(fa[x], x, p, d + w[x]);
for (int j = 0; j < deg[x]; ++j) {
int y = son[x][j];
if (y != pre) getdis(y, x, p, d + w[y]);
}
}
bool cmp(int x, int y) {
if (dis[now][x] != dis[now][y])
return dis[now][x] < dis[now][y];
return x < y;
}
// 将“x 的最近叶子”转换成“父亲的最近叶子”。
// 仅外部叶子的状态需要改变,内部叶子的状态保持不变。
void cross(int x) {
int l = 0, r = 0, j = 1;
for (int i = 1; i <= n; ++i) {
int p = ord[x][i];
if (inside(x, p)) continue;
while (j <= n && dis[x][ord[x][j]] <= dis[x][p]) {
int q = ord[x][j++];
if (!inside(x, q) || f[x][q] == NEG) continue;
while (l < r && f[x][que[r - 1]] <= f[x][q]) --r;
que[r++] = q;
}
while (l < r && dis[x][que[l]] < dis[x][p] - 2 * w[x]) ++l;
if (l < r) f[x][p] = max(f[x][p], f[x][que[l]]);
}
}
// 判断是否存在叶集,使 a * D - b * W > 0。
bool check(int a, int b) {
for (int x = tot; x >= 1; --x) {
if (!deg[x]) {
fill(f[x] + 1, f[x] + n + 1, NEG);
f[x][id[x]] = 0;
} else {
int l = son[x][0], r = son[x][1];
ll cl = (ll)b * w[l], cr = (ll)b * w[r];
for (int p = 1; p <= n; ++p) {
ll v = NEG;
if (!inside(r, p)) v = max(v, f[l][p] - cl);
if (!inside(l, p)) v = max(v, f[r][p] - cr);
if (f[l][p] != NEG && f[r][p] != NEG) {
ll z = f[l][p] + f[r][p] - cl - cr;
// x 是所有被选叶子的 LCA:没有父边,不是三度点。
if (inside(x, p) && z > 0) return true;
// 父边也使用时,x 是三度点,增加最近叶子距离。
v = max(v, z + (ll)a * dis[x][p]);
}
f[x][p] = v;
}
}
if (x != 1) cross(x);
}
return false;
}
int main() {
freopen("biscuit.in", "r", stdin);
freopen("biscuit.out", "w", stdout);
scanf("%d", &n);
tot = 2 * n - 1;
for (int x = 2; x <= tot; ++x) {
scanf("%d%d", &fa[x], &w[x]);
son[fa[x]][deg[fa[x]]++] = x;
}
dfs(1);
for (int p = 1; p <= n; ++p)
getdis(leaf[p], 0, p, 0);
for (int x = 1; x <= tot; ++x) {
now = x;
for (int p = 1; p <= n; ++p) ord[x][p] = p;
sort(ord[x] + 1, ord[x] + n + 1, cmp);
}
// 三位小数相邻答案的分界为 (2 * mid + 1) / 2000。
// 恰好等于分界时应向上舍入,所以判断必须使用严格大于零。
int l = 500, r = 1000;
while (l < r) {
int mid = (l + r) >> 1;
int p = 2 * mid + 1;
if (check(p, 2000 - p)) r = mid;
else l = mid + 1;
}
printf("%d.%03d\n", l / 1000, l % 1000);
return 0;
}
题解:https://files.cnblogs.com/files/blogs/832279/dessert_solutions(1).zip?t=1791353940&download=true

浙公网安备 33010602011771号