CF809E Surprise me!

Posted Cyhlnj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF809E Surprise me!相关的知识,希望对你有一定的参考价值。

题意

给你一棵\(n\) 个点的树,每个点有权值 \(a_i\)?
\(a\) 为一个排列

\[\frac{1}{n(n?1)}?\sum_{i=1}^{n}\sum_{j=1}^{n}\varphi(a_ia_j)dist_{i,j}\]
\(n≤200000\)
答案对 \(10^9+7\) 取模

Sol

莫比乌斯反演
然后要求
\[\sum_{d=1}^{n}\frac{d}{\varphi(d)}\sum{i=1}{\lfloor\frac{n}{d}\rfloor}\mu(i)F(i*d)\]
其中
\(F(d)=\sum_{d|a_i}\sum_{d|a_j}\varphi(a_i)\varphi(a_j)dist(i,j)\)

直接把\(F(d)\)求出来,把满足要求的点拿出来建虚树\(DP\)就好了

# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

const int maxn(2e5 + 5);
const int mod(1e9 + 7);

typedef int Arr[maxn];

int n, cnt, idx, tot, len, ret;
Arr dfn, size, fa, first1, first2, s, deep, id;
int lg[maxn << 1], st[20][maxn << 1];
Arr a, prime, isprime, phi, mu, f, mark, sum;
vector <int> p[maxn], fac[maxn];

struct Edge{
    int to, next;
} e1[maxn << 1], e2[maxn];

IL int Pow(RG ll x, RG ll y){
    RG ll ret = 1;
    for(; y; y >>= 1, x = x * x % mod)
        if(y & 1) ret = ret * x % mod;
    return ret;
}

IL void Add1(RG int u, RG int v){
    e1[cnt] = (Edge){v, first1[u]}, first1[u] = cnt++;
}

IL void Add2(RG int u, RG int v){
    e2[cnt] = (Edge){v, first2[u]}, first2[u] = cnt++;
}

IL void Dfs(RG int u){
    size[u] = 1, dfn[u] = ++idx, st[0][id[u] = ++len] = u;
    for(RG int i = 0, j = fac[a[u]].size(); i < j; ++i)
        p[fac[a[u]][i]].push_back(u);
    for(RG int e = first1[u]; e != -1; e = e1[e].next){
        RG int v = e1[e].to;
        if(!size[v]){
            deep[v] = deep[u] + 1;
            Dfs(v), size[u] += size[v];
            fa[v] = u, st[0][++len] = u;
        }
    }
}

IL int Min(RG int x, RG int y){
    return deep[x] < deep[y] ? x : y;
}

IL int LCA(RG int u, RG int v){
    u = id[u], v = id[v];
    if(u > v) swap(u, v);
    RG int lgn = lg[v - u + 1];
    return Min(st[lgn][u], st[lgn][v - (1 << lgn) + 1]);
}

IL int Dis(RG int u, RG int v){
    RG int lca = LCA(u, v);
    return deep[u] + deep[v] - 2 * deep[lca];
}

IL void Upd(RG int &x, RG int y){
    x += y;
    if(x >= mod) x -= mod;
}

IL void DP(RG int u){
    sum[u] = mark[u] * phi[a[u]];
    Upd(ret, mod - 1LL * sum[u] * sum[u] % mod * deep[u] % mod);
    for(RG int e = first2[u]; e != -1; e = e2[e].next){
        RG int v = e2[e].to;
        DP(v);
        Upd(ret, mod - 2LL * sum[u] * sum[v] % mod * deep[u] % mod);
        Upd(sum[u], sum[v]);
    }
}

IL int Calc(RG int x){
    RG int l = p[x].size(), ret1 = 0, ret2 = 0, t = 0; cnt = 0;
    for(RG int i = 0; i < l; ++i) first2[p[x][i]] = -1, mark[p[x][i]] = 1;
    for(RG int i = 0; i < l; ++i){
        RG int lca = s[t] ? LCA(s[t], p[x][i]) : 0;
        if(lca == s[t]) s[++t] = p[x][i];
        else{
            while(t > 1 && deep[lca] <= deep[s[t - 1]]) Add2(s[t - 1], s[t]), --t;
            if(s[t] != lca) first2[lca] = -1, Add2(lca, s[t]), s[t] = lca;
            s[++t] = p[x][i];
        }
    }
    while(t > 1) Add2(s[t - 1], s[t]), --t;
    for(RG int i = 0; i < l; ++i){
        Upd(ret1, phi[a[p[x][i]]]);
        Upd(ret2, 1LL * deep[p[x][i]] * phi[a[p[x][i]]] % mod);
    }
    ret = 0;
    DP(s[1]), Upd(ret, ret);
    Upd(ret, 2LL * ret1 * ret2 % mod);
    for(RG int i = 0; i < l; ++i) mark[p[x][i]] = 0;
    return ret;
}

IL void Sieve(){
    phi[1] = mu[1] = 1;
    for(RG int i = 2; i <= n; ++i){
        if(!isprime[i]) prime[++tot] = i, phi[i] = i - 1, mu[i] = -1;
        for(RG int j = 1; j <= tot && i * prime[j] <= n; ++j){
            isprime[i * prime[j]] = 1;
            if(i % prime[j]){
                phi[i * prime[j]] = phi[i] * phi[prime[j]];
                mu[i * prime[j]] = -mu[i];
            }
            else{
                phi[i * prime[j]] = phi[i] * prime[j];
                mu[i * prime[j]] = 0;
                break;
            }
        }
    }
    for(RG int i = 1; i <= n; ++i)
        for(RG int j = 1; j * i <= n; ++j) fac[j * i].push_back(i);
}

int main(){
    n = Input(), Sieve();
    for(RG int i = 1; i <= n; ++i) first1[i] = first2[i] = -1, a[i] = Input();
    for(RG int i = 1; i < n; ++i){
        RG int u = Input(), v = Input();
        Add1(u, v), Add1(v, u);
    }
    Dfs(1);
    for(RG int i = 2; i <= len; ++i) lg[i] = lg[i >> 1] + 1;
    for(RG int j = 1; j <= lg[len]; ++j)
        for(RG int i = 1; i + (1 << j) - 1 <= len; ++i)
            st[j][i] = Min(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]);
    for(RG int i = 1; i <= n; ++i) f[i] = Calc(i);
    RG int ans = 0;
    for(RG int i = 1; i <= n; ++i){
        RG int ret = 0;
        for(RG int j = 1, t = n / i; j <= t; ++j)
            Upd(ret, 1LL * (mu[j] + mod) % mod * f[i * j] % mod);
        ret = 1LL * ret * i % mod;
        Upd(ans, 1LL * ret * Pow(phi[i], mod - 2) % mod);
    }
    ans = 1LL * ans * Pow(1LL * n * (n - 1) % mod, mod - 2) % mod;
    printf("%d\n", ans);
    return 0;
}

以上是关于CF809E Surprise me!的主要内容,如果未能解决你的问题,请参考以下文章

CF809E Surprise me!

CF809E Surprise me! 莫比乌斯反演虚树树形DP

One day one cf,Keep Wa away from me.

ModuleNotFoundError:没有名为'surprise'的模块

如何从后台弹出片段

python 安装surprise库解决 c++tools错误问题