zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    乱七八糟想到什么记什么1
    ubuntu下 安装python module的步骤 分类: python Module 2013-10-12 13:58 624人阅读 评论(0) 收藏
    python中文编码转换 分类: python基础学习 python 小练习 2013-10-11 17:22 331人阅读 评论(0) 收藏
    from ....import导入其他路径的模块 分类: python基础学习 2013-10-11 15:13 315人阅读 评论(0) 收藏
    贪婪 vs 不贪婪 分类: 正则表达式 2013-10-09 15:00 290人阅读 评论(0) 收藏
    删除列表元素时需注意的问题 分类: python基础学习 python 小练习 2013-10-09 14:02 293人阅读 评论(0) 收藏
    #小练习 输出1到100的质数 分类: python 小练习 2013-10-08 17:45 319人阅读 评论(0) 收藏
    Linux下python升级至2.7步骤 分类: python基础学习 python下载 2013-09-29 11:24 4266人阅读 评论(2) 收藏
    实例、类、父类的关系判断 分类: python基础学习 2013-09-27 10:47 614人阅读 评论(0) 收藏
    #小练习 替换文件某行内容 分类: python 小练习 python Module 2013-09-26 11:10 269人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/pkh68/p/11475495.html
Copyright © 2011-2022 走看看