【考试总结2021-02-24】执行

A.gift

考虑交换次数是置换的阶 (-1),那么答案就是 (n-) 环数

考虑把已知的连通块表示一下,链首和链尾可能分别是 (0 o id,id o 0,0 o 0,id o id)

已经是环的部分直接统计答案

求出来这几种情况的方案是 (trivial) 的,这个直接做就行

这四种环需要合并,可以用 (0 o 0) 来作为 (id o 0,0 o id) 的媒介,(id o id) 的部分会在 $0 o 0 $ 中出现

(f_i)(i) 个环的方案数,(g_i) 是至少 (i) 个环的

钦定 (j) 个形成 (i) 个环,剩下的随便连,得到式子

(g_i=sum_{j=i}^n inom n jegin{bmatrix}i\ jend {bmatrix} A(n+m-j,n-j))

二项式反演得到

[f(n)=sum_{i=n}^m inom i n g(i)Leftrightarrow g(n)=sum_{i=n}^m (-1) ^{i-n} inom i n f(i) ]

[f_i=sum_{j=i}^ninom nj egin{bmatrix} i\ j end{bmatrix}frac{(n+m-j-1)!}{(m-1)!} ]

那么分别对 $c_{0,id},c_{id,0} $ 作为多项式的次数进行卷积即可

B.girls

先容斥,答案为不考虑互斥减掉至少一个互斥的,再减掉两个互斥的,加上图上三元环的带权贡献

貌似分开计数就行了,图上三元环计数的方法是按照出度排序,原图中的边,小的点向大的点连边

枚举 (1 o n),先标记出点,再在出点的出点里面找被标记点就行了

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define For(i,a,b) for(register int i=a;i<=b;++i)
#define Down(i,a,b) for(register int i=a;i>=b;i--)
#define reg register
inline int min(int x, int y) {
    return x < y ? x : y;
}
inline int max(int x, int y) {
    return x > y ? x : y;
}
inline void swap(int &x, int &y) {
    int t = x;
    x = y;
    y = t;
    return ;
}
namespace yspm {
inline int read() {
    int res = 0, f = 1;
    char k;

    while (!isdigit(k = getchar()))
        if (k == '-')
            f = -1;

    while (isdigit(k))
        res = res * 10 + k - '0', k = getchar();

    return res * f;
}
const int N = 2e5 + 10;
int head[N], cnt, n, m, id[N], q[N], deg[N];
vector<int>f[N], g[N];
ull A, B, C, ans;
bool vis[N];
struct node {
    int to, nxt;
} e[N << 1];
inline bool cmp(int x, int y) {
    return deg[x] > deg[y];
}
inline void add(int u, int v) {
    e[++cnt].nxt = head[u];
    e[head[u] = cnt].to = v;
    deg[u]++;
    f[u].push_back(v);
    return ;
}
signed main() {
    //      freopen("1.in","r",stdin);
    n = read();
    m = read();
    A = read(), B = read(), C = read();

    for (reg int i = 1, u, v; i <= m; ++i)
        u = read(), v = read(), add(u, v), add(v, u);

    for (reg int i = 0; i < n; ++i) {
        sort(f[i].begin(), f[i].end());

        if (i + 2 < n)
            ans += A * ((n - i - 2) * (n - i - 1) / 2) * i;

        if (i + 1 < n)
            ans += (i * (n - i - 1)) * B * i;

        if (i - 2 >= 0)
            ans += (i - 1) * i / 2 * C * i;
    }

    for (reg int x = 0; x < n; ++x)
        for (reg int i = head[x]; i; i = e[i].nxt) {
            int t = e[i].to;

            if (t < x)
                continue;

            ans -= (n - 1 - t) * (x * A + t * B) + C * ((n - 1) * n / 2 - (t + 1) * t / 2);
            ans -= (t - x - 1) * (x * A + t * C) + B * (t * (t - 1) / 2 - (x + 1) * x / 2);
            ans -= x * (x * B + t * C) + A * x * (x - 1) / 2;
        }

    for (reg int x = 0; x < n; ++x) {
        ull sum = 0, c = 0;

        for (reg int i = head[x]; i; i = e[i].nxt)
            if (e[i].to > x)
                sum += e[i].to, ++c;

        for (reg int i = head[x]; i; i = e[i].nxt)
            if (e[i].to < x)
                ans += e[i].to * A * c + x * B * c + sum * C;

        c = 0;
        sum = 0;

        for (reg int j = ((int)f[x].size()) - 1; j >= 0 && f[x][j] > x; --j)
            ans += x * A * c + f[x][j] * B * c + sum * C, sum += f[x][j], ++c;

        sum = 0;
        c = 0;

        for (reg int i = 0; i < f[x].size() && f[x][i] < x; ++i)
            ans += sum * A + f[x][i] * B * c + x * C * c, sum += f[x][i], ++c;
    }

    for (reg int i = 0; i < n; ++i)
        q[i] = i;

    sort(q, q + n, cmp);

    for (reg int i = 0; i < n; ++i)
        id[q[i]] = i;

    For(x, 0, n - 1) for (reg int i = head[x]; i; i = e[i].nxt)
        if (id[e[i].to] > id[x])
            g[x].push_back(e[i].to);

    For(i, 0, n - 1) {
        int now = q[i];

        for (auto p : g[now])
            vis[p] = 1;

        for (auto t : g[now])
            for (auto z : g[t]) {
                if (!vis[z])
                    continue;

                int fir = now, sec = t, thi = z;

                if (sec < fir)
                    swap(sec, fir);

                if (thi < fir)
                    swap(thi, fir);

                if (thi < sec)
                    swap(sec, thi);

                ans -= sec * B + fir * A + thi * C;
            }

        for (auto p : g[now])
            vis[p] = 0;
    }
    printf("%lld
", ans);
    return 0;
}
}
signed main() {
    return yspm::main();
}

C.string

题目中的要求都是广义 (sam) 的基操

写个支持链加的 (lct) 每个点上维护 (20) 个串的 (endpos) 信息

对于版本,开 (n)(vector) 记一下每个串最后一次被修改,查的时候 (upper\_bound-1)

剩下的就是写了

原文地址:https://www.cnblogs.com/yspm/p/14444890.html