2026.7.6 考试总结
烤柿总结
估分:100 + 100 + 30 + 100
实际:100 + 100 + 30 + 100
可惜没有时间做 t3 了 qwqwqwqwqw
walk
我们发现对于满足限制的时间 \(t\) 构成一个线性同余方程,于是对于每种颜色一直 excrt 合并即可。
记得开 __int128。
code
#include <bits/stdc++.h>
using namespace std;
#define int __int128
#define ll long long
#define usd unsigned
#define el cout << '\n'
#define lowbit(x) (x & (-x))
const int ranmod = 1e7;
#define random ((rand() * rand()) % ranmod)
#define AC return
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
// void init();
void ACehomoxue();
signed main() {
freopen("walk.in", "r", stdin);
freopen("walk.out", "w", stdout);
int t = 1;
cout << fixed << setprecision(15);
// cin >> t;
while(t--) {
// init();
ACehomoxue();
}
AK;
}
inline int read(){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
void print(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
return;
}
il istream& operator >>(istream& in, __int128 &a) { a = read(); return in; }
il ostream& operator <<(ostream& in, __int128 &a) { print(a); return in; }
const int mod = 998244353, maxn = 2 * 1e5 + 18;
il int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }
il int lcm(int a, int b) { return a / gcd(a, b) * b; }
il int exgcd(int a, int b, int &x, int &y) {
if(!b) { x = 1, y = 0; return a; }
else {
int g = exgcd(b, a % b, y, x);
y -= a / b * x;
return g;
}
}
il pii excrt(pii pi1, pii pi2) {
int a1 = pi1.first, p1 = pi1.second, a2 = pi2.first, p2 = pi2.second, k1{}, k2{};
if(a1 == -1 || p1 == -1 || a2 == -1 || p2 == -1) return {-1, -1};
int t = gcd(p1, p2), modd = p1 / t * p2;
if((a2 - a1) % t) return {-1, -1};
t = (a2 - a1) / t;
exgcd(p1, p2, k1, k2);
k1 = (k1 * t % modd + modd) % modd, k2 = k2 * -t;
return {(a1 + k1 * p1 % modd) % modd, modd};
}
int n, m, l, r, s[maxn], lc = 1, ans = 0, cnt[maxn];
pii p[maxn];
vector <int> vec[maxn];
il int calc(int t, int a, int p) {
return t / p + (t % p >= a);
}
void ACehomoxue() {
cin >> n >> m >> l >> r;
for(int i = 1; i <= n; i++) {
cin >> s[i];
lc = lcm(lc, s[i]);
vec[i].push_back(s[i]);
for(int j = 1; j <= s[i]; j++) {
int x;
cin >> x;
vec[i].push_back(x);
}
}
for(int i = 1; i <= n; i++) {
for(int k = 1, t, x; k <= s[i]; k++) {
t = k % s[i], x = vec[i][k];
pii tmp = {t, s[i]};
cnt[x]++;
if(!p[x].first && !p[x].second) p[x] = tmp;
else p[x] = excrt(p[x], tmp);
}
}
for(int i = 1; i <= m; i++) {
if(p[i].second != lc || cnt[i] != n) continue;
ans = ans - calc(l - 1, p[i].first, p[i].second) + calc(r, p[i].first, p[i].second);
}
cout << ans;
}
air
注意到每个质因数之间没有关系,于是把每个质因数拆开算。对于质因数 \(p_i\),显然至少有一个包含 \(a_i\),至少一个数包含 \(b_i\),且所有都应在 \([a_i, b_i]\) 范围内,那么容斥可得方案数:
\[(b_i - a_i + 1) ^ n - 2 (b_i - a_i) ^ n + (b_i - a_i - 1) ^ n
\]
乘起来即可。做完了。
code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el cout << '\n'
#define lowbit(x) (x & (-x))
const int ranmod = 1e7;
#define random ((rand() * rand()) % ranmod)
#define AC return
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
// void init();
void ACehomoxue();
signed main() {
ios :: sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
freopen("air.in", "r", stdin);
freopen("air.out", "w", stdout);
int t = 1;
cout << fixed << setprecision(15);
// cin >> t;
while(t--) {
// init();
ACehomoxue();
}
AK;
}
const int mod = 998244353, maxn = 1e6 + 18;
il int ksm(int a, int k = mod - 2) { int res = 1; for(; k; k >>= 1, a = a * a % mod) if(k & 1) res = res * a % mod; return res; }
int m, n, a[maxn], b[maxn], ans = 1;
il int calc(int x) {
if(x <= 0) return 0;
if(x == 1) return 1;
if(x == 2) return Mod(ksm(x, n) - 2);
return Mod(ksm(x, n) - 2 * ksm(x - 1, n) + ksm(x - 2, n));
}
void ACehomoxue() {
cin >> m >> n;
for(int i = 1; i <= m; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> b[i];
for(int i = 1; i <= m; i++) ans = ans * calc(b[i] - a[i] + 1) % mod;
cout << ans;
el;
}
dimension
利用组合意义并推式子,我们知道我们要求的其实是:
\[\sum_{k = 0} ^ n \sum_{i = 0} ^ n \binom{i}{k}
\]
上指标求和可得:
\[原式 = \sum_{k = 0} ^ m \binom{n + 1}{k + 1}
\]
\[= \sum_{k = 0} ^ {m + 1} \binom{n + 1}{k} - 1
\]
我们设 \(F(n, m) = \sum_{i = 0} ^ m \binom{n}{i}\),那么答案就应为 \(F(n + 1, m + 1) - 1\),于是我们只需考虑如何快速求 \(F\) 函数即可。注意到模数较小,卢卡斯定理拆开:
\[F(n, m) = \sum_{i = 0} ^ m \binom{n \bmod p}{i \bmod p} \binom{\lfloor \frac n p \rfloor}{\lfloor \frac i p \rfloor}
\]
继续拆,得:
\[F(n, m) = \sum_{i = 0} ^ {\lfloor \frac m p \rfloor - 1} \binom{\lfloor \frac n p \rfloor}{i} \sum_{j = 0} ^ {p - 1} \binom{n \bmod p}{j} + \binom{\lfloor \frac n p \rfloor}{\lfloor \frac m p \rfloor} \sum_{i = 0} ^ {m \bmod p} \binom{n \bmod p}{i}
\]
\[= \sum_{i = 0} ^ {p - 1} \binom{n \bmod p}{i} F(\lfloor \frac n p \rfloor, \lfloor \frac m p \rfloor - 1) + \binom{\lfloor \frac n p \rfloor}{\lfloor \frac m p \rfloor} \sum_{i = 0} ^ {m \bmod p} \binom{n \bmod p}{i}
\]
\[= F(\lfloor \frac n p \rfloor, \lfloor \frac m p \rfloor - 1)\sum_{i = 0} ^ {p - 1} \binom{n \bmod p}{i} + \binom{\lfloor \frac n p \rfloor}{\lfloor \frac m p \rfloor} \sum_{i = 0} ^ {m \bmod p} \binom{n \bmod p}{i}
\]
直接计算即可,其中组合数的计算记得也用卢卡斯定理。做完了。
code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el cout << '\n'
#define lowbit(x) (x & (-x))
const int ranmod = 1e7;
#define random ((rand() * rand()) % ranmod)
#define AC return
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
// void init();
void ACehomoxue();
signed main() {
ios :: sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
freopen("dimension.in", "r", stdin);
freopen("dimension.out", "w", stdout);
int t = 1;
cout << fixed << setprecision(15);
// cin >> t;
while(t--) {
// init();
ACehomoxue();
}
AK;
}
const int maxn = 1145, maxm = 2 * 1e7;
int n, m, mod, ans = 0;
int fact[maxm], inv[maxm];
il int ksm(int a, int k = mod - 2) { int res = 1; for(; k; k >>= 1, a = a * a % mod) if(k & 1) res = res * a % mod; return res; }
il int binom(int n, int m) { if(n < 0 || m < 0 || n - m < 0) AK; return fact[n] * inv[m] % mod * inv[n - m] % mod; }
void pre(int maxn = mod) {
fact[0] = 1;
for(int i = 1; i < maxn; i++) fact[i] = fact[i - 1] * i % mod;
inv[maxn - 1] = ksm(fact[maxn - 1]);
for(int i = maxn - 2; i + 1; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
il int lucas(int n, int m) {
if(n < 0 || m < 0 || n - m < 0) AK;
if(!m) return 1;
return binom(n % mod, m % mod) * lucas(n / mod, m / mod) % mod;
}
il int F(int n, int m) {
m = min(n, m);
if(m < 0) AK;
int ans = 0;
if(n >= mod || m >= mod) {
int tmp = F(n / mod, m / mod - 1);
for(int i = 0; i < mod; i++) {
ans = (ans + lucas(n % mod, i) * tmp % mod) % mod;
}
}
for(int i = 0; i <= m % mod; i++) {
ans = (ans + lucas(n / mod, m / mod) * lucas(n % mod, i) % mod) % mod;
}
return ans;
}
void ACehomoxue() {
cin >> n >> m >> mod;
pre();
cout << Mod(F(n + 1, m + 1) - 1);
el;
}
challenge
先套路化的概率转计数,注意到对于一条路径长度,可以拆成 \(dep_{u} + dep_{v} - 2 \times dep_{\text{lca}(u, v)}\)。我们考虑一个点一个点算贡献,首先要按点权降序,对于每一个点权,先算答案,然后再把这个点权的点的贡献加进去,那么现在只用考虑如何算贡献即可。
对于算贡献,假设我们在算点 \(x\),那么我们只需快速算出其每一个祖先作为 lca 时的贡献。考虑树剖,并用 5 个树状数组维护子树中已有的点数,子树中已有的点的深度和,子树去掉重儿子的点数和点权和,子树去掉重儿子的点数 \(\times dep_i\)。直接计算即可,具体细节看代码。
code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el cout << '\n'
#define lowbit(x) (x & (-x))
const int ranmod = 1e7;
#define random ((rand() * rand()) % ranmod)
#define AC return
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
// void init();
void ACehomoxue();
signed main() {
ios :: sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
freopen("challenge.in", "r", stdin);
freopen("challenge.out", "w", stdout);
int t = 1;
cout << fixed << setprecision(15);
// cin >> t;
while(t--) {
// init();
ACehomoxue();
}
AK;
}
const int maxn = 8 * 1e5 + 18, mod = 998244353;
il int ksm(int a, int k = mod - 2) { int res = 1; for(; k; k >>= 1, a = a * a % mod) if(k & 1) res = res * a % mod; return res; }
int n, m, dep[maxn], a[maxn];
class BIT {
int c[maxn], b[maxn];
public:
void modify(int i, int x) { for(; i < maxn; i += lowbit(i)) c[i] = (c[i] + x) % mod, b[i]++; }
il pii query(int i) { int res = 0, cnt = 0; for(; i; i -= lowbit(i)) res = (res + c[i]) % mod, cnt += b[i]; return {res, cnt}; }
} ds1, ds2, ds3;
vector <int> vec[maxn], buc[maxn];
int in[maxn], out[maxn], dfn = 0, tot = 0, be[maxn], pa[maxn], head[maxn], siz[maxn], son[maxn], ans = 0;
void predfs(int x, int fa) {
dep[x] = dep[fa] + 1;
pa[x] = fa;
siz[x] = 1;
for(int to : vec[x]) {
if(to == fa) continue;
predfs(to, x);
siz[x] += siz[to];
if(siz[to] > siz[son[x]]) son[x] = to;
}
}
void dfs(int x, int fa) {
in[x] = ++dfn;
if(son[fa] == x) be[x] = be[fa];
else be[x] = ++tot, head[be[x]] = x;
if(son[x]) dfs(son[x], x);
for(int to : vec[x]) if(to != fa && to != son[x]) dfs(to, x);
out[x] = dfn;
}
il pii sub(int x) {
pii pr = ds3.query(out[x]), pl = ds3.query(in[x] - 1);
return {(pr.first - pl.first + mod) % mod, pr.second - pl.second};
}
il int get(int x) {
pii pr = sub(x);
int res = Mod(pr.first - (pr.second * dep[x] % mod));
for(int p = x, l, r, tmp, h; p; p = pa[head[be[p]]]) {
h = head[be[p]];
l = in[h] - 1, r = in[p] - 1;
pii pr = ds1.query(r), pl = ds1.query(l);
tmp = Mod(pr.first - pl.first + (pr.second - pl.second) * dep[x] - 2 * (ds2.query(r).first - ds2.query(l).first));
res = (res + tmp) % mod;
if(pa[h]) {
pr = sub(pa[h]), pl = sub(h);
tmp = Mod(pr.first - pl.first + (pr.second - pl.second) * (dep[x] - 2 * dep[pa[h]]));
res = (res + tmp) % mod;
}
}
return res;
}
void add(int x) {
ds3.modify(in[x], dep[x]);
ds1.modify(in[x], dep[x]);
ds2.modify(in[x], dep[x]);
for(int p = x, h; p; p = pa[head[be[p]]]) {
h = head[be[p]];
if(pa[h]) ds1.modify(in[pa[h]], dep[x]), ds2.modify(in[pa[h]], dep[pa[h]]);
}
}
void ACehomoxue() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> a[i];
buc[a[i]].push_back(i);
}
for(int i = 1, u, v; i < n; i++) {
cin >> u >> v;
vec[u].push_back(v);
vec[v].push_back(u);
}
predfs(1, 0);
dfs(1, 0);
for(int i = m; i; i--) {
for(int x : buc[i]) ans = (ans + get(x) * (m - i) % mod) % mod;
for(int x : buc[i]) add(x);
}
ans = ans * ksm(n * (n - 1) % mod) % mod;
cout << ans;
el;
}

浙公网安备 33010602011771号