• CF809E Surprise me!


    CF809E Surprise me!

    题面:Luogu

    解析

    题意即求:

    [frac{1}{n(n-1)}sum_{i=1}^{n}sum_{j=1}^{n}varphi(a_{i}a_{j})dist(i,j) ]

    其中,(a_{i})(n)的一个排列。

    首先有:(varphi(ij)=frac{dvarphi(i)varphi(j)}{varphi(d)}),其中(d=gcd(i,j)),证明带入公式即可。

    那么有:

    [sum_{i=1}^{n}sum_{j=1}^{n}varphi(a_{i}a_{j})dist(i,j) ]

    [=sum_{d=1}^{n}frac{d}{varphi(d)}sum_{i=1}^{n}sum_{j=1}^{n}[gcd(a_{i},a_{j})=d]varphi(a_{i})varphi(a_{j})dist(i,j) ]

    考虑莫比乌斯反演,设:

    [g(d)=sum_{i=1}^{n}sum_{j=1}^{n}[gcd(a_{i},a_{j})=d]varphi(a_{i})varphi(a_{j})dist(i,j) ]

    [f(d)=sum_{i=1}^{n}sum_{j=1}^{n}[d|gcd(a_{i},a_{j})]varphi(a_{i})varphi(a_{j})dist(i,j) ]

    那么有:

    [=sum_{d=1}^{n}frac{d}{varphi(d)}sum_{d|k}mu(frac{k}{d})f(k) ]

    求出(f(k))后枚举倍数贡献即可(O(nlogn))统计答案,考虑如何计算(f(k))

    观察到只有(a_{i})(k)的倍数才有贡献,那我们把(k)的倍数的点提出来建虚树。

    现在就是求:

    [sum_{i=1}^{t}sum_{j=1}^{t}varphi(a_{i})varphi(a_{j})dist(i,j) ]

    [=sum_{i=1}^{t}varphi(a_{i})dep[i]sum_{j=1}^{t}varphi(a_{j})+sum_{i=1}^{t}varphi(a_{i})sum_{j=1}^{t}varphi(a_{j})dep[j]-2*sum_{i=1}^{t}sum_{j=1}^{t}varphi(a_{i})varphi(a_{j})d[lca] ]

    前面两部分可以(O(n))统计,后面一部分可以枚举(lca),组合一下子树,也可以(O(n))统计。

    那么总复杂度即为(O(nlogn)),解决了这个问题。

    代码

    
    #include<cstdio>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    inline int In(){
        char c=getchar();
        int x=0,ft=1;
        for(;c<'0'||c>'9';c=getchar()){
            if(c=='-'){
                ft=-1;
            }
        }
        for(;c>='0'&&c<='9';c=getchar()){
            x=x*10+c-'0';
        }
        return x*ft;
    }
    
    const int P=1e9+7,N=2e5+5;
    
    inline void Add(int& x,int y){
        x+=y;
        if(x>=P){
            x-=P;
        }
    }
    
    inline int Mul(int x,int y){
        return 1ll*x*y%P;
    }
    
    int n,a[N],pos[N],inv[N];
    int h[N],e_tot=0;
    struct Edge{
        int to,nex;
        Edge(){}
        Edge(int to,int nex):to(to),nex(nex){}
    }e[N<<1];
    
    inline void add(int u,int v){
        e[++e_tot]=Edge(v,h[u]);
        h[u]=e_tot;
    }
    
    int d[N],fa[N],sz[N],son[N];
    
    void dfs1(int u,int pre){
        d[u]=d[pre]+1;
        fa[u]=pre;
        sz[u]=1;
        for(int i=h[u],v;i;i=e[i].nex){
            v=e[i].to;
            if(v==fa[u]){
                continue;
            }
            dfs1(v,u);
            sz[u]+=sz[v];
            if(!son[u]||sz[v]>sz[son[u]]){
                son[u]=v;
            }
        }
    }
    
    int top[N],dfn[N],low[N],dfc=0;
    
    void dfs2(int u,int pre){
        top[u]=pre;
        dfn[u]=++dfc;
        if(son[u]){
            dfs2(son[u],pre);
        }
        for(int i=h[u],v;i;i=e[i].nex){
            v=e[i].to;
            if(v==fa[u]||v==son[u]){
                continue;
            }
            dfs2(v,v);
        }
        low[u]=dfc;
    }
    
    inline int LCA(int x,int y){
        while(top[x]!=top[y]){
            if(d[top[x]]<d[top[y]]){
                swap(x,y);
            }
            x=fa[top[x]];
        }
        return d[x]<d[y]?x:y;
    }
    
    int p[N],pc,mu[N],phi[N];
    bool vis[N];
    
    void Sieve(int n){
        mu[1]=phi[1]=1;
        for(int i=2;i<=n;++i){
            if(!vis[i]){
                p[++pc]=i;
                mu[i]=-1;
                phi[i]=i-1;
            }
            for(int j=1;j<=pc;++j){
                if(1ll*i*p[j]>n){
                    break;
                }
                vis[i*p[j]]=1;
                if(i%p[j]){
                    mu[i*p[j]]=-mu[i];
                    phi[i*p[j]]=phi[i]*(p[j]-1);
                }
                else{
                    mu[i*p[j]]=0;
                    phi[i*p[j]]=phi[i]*p[j];
                    break;
                }
            }
        }
    }
    
    int t[N<<1],tc,stk[N];
    vector<int> E[N];
    
    inline bool cmp(int a,int b){
        return dfn[a]<dfn[b];
    }
    
    inline void add_edge(int u,int v){
        E[u].push_back(v);
    }
    
    int ans,sum1,sum2,sum3,sum[N],f[N],g[N];
    bool fg[N];
    
    void dfs(int u){
        if(fg[u]){
            Add(sum1,phi[a[u]]);
            Add(sum2,Mul(phi[a[u]],d[u]));
            sum[u]=phi[a[u]];
            Add(sum3,Mul(d[u],Mul(phi[a[u]],phi[a[u]])));
        }
        for(int i=0,v;i<E[u].size();++i){
            v=E[u][i];
            dfs(v);
            Add(sum3,Mul(d[u],Mul(2,Mul(sum[u],sum[v]))));
            Add(sum[u],sum[v]);
        }
    }
    
    void del(int u){
        sum[u]=fg[u]=0;
        for(int i=0,v;i<E[u].size();++i){
            v=E[u][i];
            del(v);
        }
        E[u].clear();
    }
    
    int main(){
        n=In();
        for(int i=1;i<=n;++i){
            a[i]=In();
            pos[a[i]]=i;
        }
        for(int i=1,u,v;i<n;++i){
            u=In();
            v=In();
            add(u,v);
            add(v,u);
        }
        dfs1(1,0);
        dfs2(1,1);
        Sieve(n);
        inv[0]=inv[1]=1;
        for(int i=2;i<=n;++i){
            inv[i]=Mul(P-P/i,inv[P%i]);
        }
        for(int d=1;d<=n;++d){
            tc=0;
            for(int i=d;i<=n;i+=d){
                t[++tc]=pos[i];
                fg[pos[i]]=1;
            }
            sort(t+1,t+1+tc,cmp);
            for(int i=tc;i>1;--i){  
                t[++tc]=LCA(t[i-1],t[i]);
            }
            sort(t+1,t+1+tc,cmp);
            tc=unique(t+1,t+1+tc)-t-1;
            stk[1]=t[1];
            for(int i=2,stp=1;i<=tc;++i){
                while(stp&&low[stk[stp]]<dfn[t[i]]){
                    --stp;
                }
                add_edge(stk[stp],t[i]);
                stk[++stp]=t[i];
            }
            sum1=sum2=sum3=0;
            dfs(t[1]);
            Add(f[d],Mul(2,Mul(sum1,sum2)));
            Add(f[d],P-Mul(2,sum3));
            del(t[1]);
        }
        for(int d=1;d<=n;++d){
            for(int i=d;i<=n;i+=d){
                Add(g[d],Mul(f[i],(mu[i/d]+P)%P));
            }
        }
        for(int d=1;d<=n;++d){
            Add(ans,Mul(Mul(d,inv[phi[d]]),g[d]));
        }
        printf("%d
    ",Mul(Mul(inv[n-1],inv[n]),ans));
        return 0;
    }
    
    
  • 相关阅读:
    SQL Server 基础知识/数据类型/数值类型
    javascript中slice(),splice(),split(),substring(),substr()使用方法
    Sublime text设置快捷键让编写的HTML文件在打指定浏览器预览
    常用开发环境配置和使用技巧
    JavaScript 模块化简析
    MySQL重置root用户密码的方法(转)
    SpringMVC 文件上传配置,多文件上传,使用的MultipartFile(转)
    Postman 安装及使用入门教程(转)
    HTTP状态码:400500 错误代码
    (转)Eclipse快捷键大全,导包快捷键:ctrl+Shift+/
  • 原文地址:https://www.cnblogs.com/pkh68/p/11475495.html
Copyright © 2020-2023  润新知