20250919

T1

蒜头看演出

异或哈希即可。

代码
#include <iostream>
#include <string.h>
#include <random>
#include <set>
#include <map>
using namespace std;
random_device rd;
mt19937_64 mtrand(rd());
int n, m;
unsigned long long cnt[100005];
map<unsigned long long, int> ccnt;
int ans[100005];
set<unsigned long long> st;
map<unsigned long long, set<int> > _st;
int main() {
    freopen("actor.in", "r", stdin);
    freopen("actor.out", "w", stdout);
    cin >> n >> m;
    ccnt[0] = n;
    for (int i = 1; i <= n; i++) _st[0].insert(i);
    for (int i = 1; i <= m; i++) {
        unsigned long long V = mtrand();
        int k, x;
        cin >> k;
        while (k--) {
            cin >> x;
            if (ans[x]) continue;
            if (ccnt[cnt[x]] == 1) st.erase(cnt[x]);
            else if (ccnt[cnt[x]] == 2) st.insert(cnt[x]);
            --ccnt[cnt[x]];
            _st[cnt[x]].erase(x);
            cnt[x] ^= V;
            _st[cnt[x]].insert(x);
            if (ccnt[cnt[x]] == 0) st.insert(cnt[x]);
            else if (ccnt[cnt[x]] == 1) st.erase(cnt[x]);
            ++ccnt[cnt[x]];
        }
        if (st.size()) for (auto v : st) ans[*_st[v].begin()] = i, _st[v].clear(), --ccnt[v];
        st.clear();
    }
    for (int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
    return 0;
}

T2

老虎的迷宫

记录从父亲下来,走进子树再回来的概率,父亲活着的时候下来,死在子树里的权值期望,和父亲死了下来,死在子树里的权值期望。容易自下而上 dp 转移。

代码
#include <iostream>
#include <string.h>
#define int long long
using namespace std;
const int P = 1000000007;
inline void Madd(int &x, int y) { (x += y) >= P ? (x -= P) : 0; }
inline int Msum(int x, int y) { return Madd(x, y), x; }
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++
char buf[1<<21], *p1, *p2, ch;
long long read() {
    long long ret = 0, neg = 0; char c = getchar(); neg = (c == '-');
    while (c < '0' || c > '9') c = getchar(), neg |= (c == '-');
    while (c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
    return ret * (neg ? -1 : 1);
}
int head[1000005], nxt[2000005], to[2000005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int val[1000005], deg[1000005];
int f[2][1000005], g[1000005], sf[1000005];
int inv[1000005], tmp[2][1000005];
int n, S;
void dfs(int x, int fa) {
    int cnt = 0, st0 = 0, st1 = 0;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != fa) {
            dfs(v, x);
            ++cnt;
            Madd(sf[x], f[1][v]);
            Madd(g[x], inv[deg[x]] * g[v] % P * inv[deg[x] - 1] % P);
            Madd(g[x], inv[deg[x]] * inv[deg[v]] % P * inv[deg[x]] % P);
            Madd(f[0][x], inv[deg[x]] * f[0][v] % P);
            Madd(f[0][x], inv[deg[x]] * inv[deg[v]] % P * inv[deg[x]] % P * sf[v] % P);
            Madd(f[1][x], inv[deg[x] - 1] * f[0][v] % P);
            Madd(f[1][x], inv[deg[x] - 1] * inv[deg[v]] % P * inv[deg[x] - 1] % P * sf[v] % P);
            tmp[0][v] = inv[deg[v]];
            tmp[1][v] = g[v];
            Madd(st0, tmp[0][v]);
            Madd(st1, tmp[1][v]);
        }
    }
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != fa) {
            int t0 = Msum(st0, P - tmp[0][v]);
            int t1 = Msum(st1, P - tmp[1][v]);
            Madd(f[0][x], inv[deg[x]] * inv[deg[x]] % P * t0 % P * f[1][v] % P);
            Madd(f[0][x], inv[deg[x]] * inv[deg[x] - 1] % P * t1 % P * f[1][v] % P);
            Madd(f[1][x], inv[deg[x] - 1] * inv[deg[x] - 1] % P * t0 % P * f[1][v] % P);
            Madd(f[1][x], inv[deg[x] - 1] * inv[deg[x] - 2] % P * t1 % P * f[1][v] % P);
        }
    }
    if (cnt) {
        sf[x] = sf[x] * inv[cnt] % P;
        if (cnt == 1) Madd(f[1][x], st1 * val[x] % P);
    } else {
        f[1][x] = sf[x] = val[x];
    }
}
signed main() {
    freopen("wander.in", "r", stdin);
    freopen("wander.out", "w", stdout);
    n = read();
    for (int i = 1; i <= n; i++) val[i] = read();
    for (int i = (inv[1] = 1, 2); i <= n; i++) {
        inv[i] = (P - P / i) * inv[P % i] % P;
        int u = read(), v = read();
        add(u, v);
        add(v, u);
        ++deg[u], ++deg[v];
    }
    S = read();
    ++deg[S];
    dfs(S, 0);
    cout << f[1][S] << "\n";
    return 0;
}

T3

老虎的解码

由欧拉定理 \(x^{c} \equiv x^{c \bmod {\varphi(n)}} \pmod n\),我们希望对 \(m\)\(c\) 次根,只需要求出 \(c\) 在模 \(\varphi(n)\) 意义下的逆元。然后用 \(m^{\frac{1}{c}}\) 即得 \(x\)。而 \(\varphi(n) = (p - 1)(q - 1)\),于是只需要求出 \(p, q\)。由于保证了 \(q - p\),我们考虑枚举 \(s = p + q\)。然后解出 \(q - p = \sqrt{s^2 - 4n}\)。于是 \(s = \sqrt{(q - p)^2 + 4n}\),而 \(s \ge 2\sqrt{n}\),于是只需要从根号开始枚举,直到找到合法的 \(s\) 即可。

代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#define int __int128
using namespace std;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++
char buf[1<<21], *p1, *p2, ch;
int read() {
    int ret = 0, neg = 0; char c = getchar(); neg = (c == '-');
    while (c < '0' || c > '9') c = getchar(), neg |= (c == '-');
    while (c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
    return ret * (neg ? -1 : 1);
}
map<int, int> mp;
int n, m, c, p, q;
int qpow(int x, int y) {
    int ret = 1;
    while (y) {
        if (y & 1) 
            ret = ret * x % n;
        y >>= 1;
        x = x * x % n;
    }
    return ret;
}
void exgcd(int a, int b, int &x, int &y) {
    if (!b) return x = 1, y = 0, void();
    exgcd(b, a % b, y, x), y -= x * (a / b);
}
void _print(__int128 x) {
    string str;
    while (x) str += ('0' + x % 10), x /= 10;
    reverse(str.begin(), str.end());
    cout << str << "\n";
}
signed main() {
    freopen("rsa.in", "r", stdin);
    freopen("rsa.out", "w", stdout);
    int tc = read();
    while (tc--) {
        n = read(), m = read(), c = read();
        for (int s = 2 * sqrt((long long)n);; s++) {
            int d = sqrt((long long)(s * s - 4 * n));
            if (d * d != s * s - 4 * n) continue;
            q = (s + d) / 2, p = (s - d) / 2;
            break;
        }
        int k, _, t = (p - 1) * (q - 1);
        exgcd(c, t, k, _);
        k = (k % t + t) % t;
        _print(qpow(m, k));
    }
    return 0;
}

T4

蒜头的数论

\[\begin{equation}\begin{split} \sum\limits_{i = 1}^n\sum\limits_{j = 1}^n\sum\limits_{k = 1}^nA_iB_jC_kD_{(i, j)}E_{(i, k)}F_{(j, k)} &= \sum\limits_{i = 1}^n\sum\limits_{j = 1}^n\sum\limits_{k = 1}^n\sum\limits_{d_1}^n\sum\limits_{d_2}^n\sum\limits_{d_3}^n[(i, j) = d_1][(i, k) = d_2][(j, k) = d_3]A_iB_jC_kD_{d_1}E_{d_2}F_{d_3} \\ &= \sum\limits_{i = 1}^n\sum\limits_{j = 1}^n\sum\limits_{k = 1}^n\sum\limits_{d_1}^n\sum\limits_{d_2}^n\sum\limits_{d_3}^n\sum\limits_{d_1 | e_1}\sum\limits_{d_2 | e_2}\sum\limits_{d_3 | e_3}[e_1 | (i, j)][e_2 | (i, k)][e_3 | (j, k)]\mu(\frac{e_1}{d_1})\mu(\frac{e_2}{d_2})\mu(\frac{e_3}{d_3})A_iB_jC_kD_{d_1}E_{d_2}F_{d_3} \\ &= \sum\limits_{e_1}\sum\limits_{e_2}\sum\limits_{e_3}\sum\limits_{d_1 | e_1}^n\sum\limits_{d_2 | e_2}^n\sum\limits_{d_3 | e_3}^n\sum\limits_{e_1 | i, e_2 | i}^n\sum\limits_{e_1 | j, e_3 | j}^n\sum\limits_{e_2 | k, e_3 | k}^n\mu(\frac{e_1}{d_1})\mu(\frac{e_2}{d_2})\mu(\frac{e_3}{d_3})A_iB_jC_kD_{d_1}E_{d_2}F_{d_3} \\ &= \sum\limits_{e_1}\sum\limits_{e_2}\sum\limits_{e_3}(\sum\limits_{d_1 | e_1}^n\mu(\frac{e_1}{d_1})D_{d_1})(\sum\limits_{d_2 | e_2}^n\mu(\frac{e_2}{d_2})E_{d_2})(\sum\limits_{d_3 | e_3}^n\mu(\frac{e_3}{d_3})F_{d_3})(\sum\limits_{\text{lcm}(e_1, e_2) | i}^nA_i)(\sum\limits_{\text{lcm}(e_1, e_3) | j}^nB_j)(\sum\limits_{\text{lcm}(e_2, e_3) | k}^nC_k) \\ \end{split}\end{equation} \]

后六个 \(\sum\) 全都是独立的,如果把 \(e_1, e_2, e_3\) 视为点,在 \(\text{lcm} \le n\) 的点之间连边,会发现这是一个三元环计数的形式,每个三元环的权值是点权积乘以边权积,要求所有三元环的权值和。直接跑三元环计数即可。注意特殊处理有重复点的环。

代码
#include <iostream>
#include <string.h>
#include <vector>
#define int long long
using namespace std;
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int n;
unsigned long long A[100005], B[100005], C[100005], D[100005], E[100005], F[100005];
unsigned long long v1[100005], v2[100005], v3[100005], e1[100005], e2[100005], e3[100005];
int pr[100005], mu[100005], pcnt;
bool mark[100005];
vector<int> vec[100005];
vector<pair<int, int> > G[100005], tmp;
int deg[100005];
void Sieve() {
    mu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!mark[i]) pr[++pcnt] = i, mu[i] = -1;
        for (int j = 1; j <= pcnt && pr[j] * i <= n; j++) {
            mark[pr[j] * i] = 1;
            if (i % pr[j] == 0) break;
            mu[i * pr[j]] = -mu[i];
        }
    }
}
unsigned long long rec[100005][6], ans;
signed main() {
    freopen("sum.in", "r", stdin);
    freopen("sum.out", "w", stdout);
    cin >> n;
    Sieve();
    for (int i = 1; i <= n; i++) cin >> A[i];
    for (int i = 1; i <= n; i++) cin >> B[i];
    for (int i = 1; i <= n; i++) cin >> C[i];
    for (int i = 1; i <= n; i++) cin >> D[i];
    for (int i = 1; i <= n; i++) cin >> E[i];
    for (int i = 1; i <= n; i++) cin >> F[i];
    for (int i = 1; i <= n; i++) for (int j = i; j <= n; j += i) {
        vec[j].emplace_back(i);
        e1[i] += A[j], e2[i] += B[j], e3[i] += C[j];
        v1[j] += mu[j / i] * D[i], v2[j] += mu[j / i] * E[i], v3[j] += mu[j / i] * F[i];
    }
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j += i) {
            for (auto v : vec[j]) if (v > i && i * v / gcd(i, v) == j) {
                ++deg[i], ++deg[v];
                tmp.emplace_back(i, v);
            }
        }
    }
    for (auto p : tmp) {
        int u = p.first, v = p.second;
        if (deg[u] < deg[v]) G[u].emplace_back(v, u * v / gcd(u, v));
        else G[v].emplace_back(u, u * v / gcd(u, v));
    }
    for (int i = 1; i <= n; i++) {
        if (!v1[i] && !v2[i] && !v3[i]) continue;
        ans += v1[i] * v2[i] * v3[i] * e1[i] * e2[i] * e3[i];
        for (auto p1 : G[i]) memset(rec[p1.first], 0, sizeof rec[p1.first]);
        for (auto p1 : G[i]) {
            int u = p1.first; int t = p1.second;
            for (auto p2 : G[u]) {
                rec[p2.first][0] += v1[i] * v2[u] * e1[t] * e3[p2.second];
                rec[p2.first][1] += v1[i] * v3[u] * e2[t] * e3[p2.second];
                rec[p2.first][2] += v2[i] * v1[u] * e1[t] * e2[p2.second];
                rec[p2.first][3] += v2[i] * v3[u] * e3[t] * e2[p2.second];
                rec[p2.first][4] += v3[i] * v1[u] * e2[t] * e1[p2.second];
                rec[p2.first][5] += v3[i] * v2[u] * e3[t] * e1[p2.second];
            }
            ans += v1[i] * v2[i] * v3[u] * e1[i] * e2[t] * e3[t];
            ans += v1[i] * v2[u] * v3[i] * e1[t] * e2[i] * e3[t];
            ans += v1[u] * v2[i] * v3[i] * e1[t] * e2[t] * e3[i];
            ans += v1[i] * v2[u] * v3[u] * e1[t] * e2[t] * e3[u];
            ans += v1[u] * v2[i] * v3[u] * e1[t] * e2[u] * e3[t];
            ans += v1[u] * v2[u] * v3[i] * e1[u] * e2[t] * e3[t];
        }
        for (auto p1 : G[i]) {
            ans += e2[p1.second] * rec[p1.first][0] * v3[p1.first];
            ans += e1[p1.second] * rec[p1.first][1] * v2[p1.first];
            ans += e3[p1.second] * rec[p1.first][2] * v3[p1.first];
            ans += e1[p1.second] * rec[p1.first][3] * v1[p1.first];
            ans += e3[p1.second] * rec[p1.first][4] * v2[p1.first];
            ans += e2[p1.second] * rec[p1.first][5] * v1[p1.first];
        }
    }
    cout << ans << "\n";
    return 0;
}

对称性的式子,推的时候可以保留对称性。

posted @ 2025-09-21 19:07  forgotmyhandle  阅读(11)  评论(0)    收藏  举报