• CF809E Surprise me!


    CF809E Surprise me! 

    考场上别人都会的原题就我不会

    被逼无奈,还是想出了这道div1的E题!

    phi(x*y)就是phi(x)*phi(y)*gcd(x,y)/phi(gcd(x,y))其实就是把公共质因子的(1-1/p)这些东西除掉

    考虑容斥

    直接枚举d,注意,这个d不是gcd,而是公共质因子乘积,所以miu(d)不能是0

    配凑容斥系数,其实就是d的所有质因子子集根据大小+1-1,例如:1/x*y*z-1/x*y-1/y*z-1/x*z+1/x+1/y+1/z,这里x=(1-1/p)这样的形式

    所有是d倍数的数,建成虚树,然后统计贡献

    其实只要枚举每个虚树的边的贡献即可处理d(u,v)

    写了半天:

    1.O(1)LCA是快,但是注意ST判断i+(1<<j)-1<=cnt,还有lim是cnt不是n!

    数组要开2倍

    2.虚树还是注意mem[i]不是i

    3.明确枚举的公共质因子而不是gcd!

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    // #define int long long 
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    namespace Modulo{
    const int mod=1e9+7;
    int ad(int x,int y){return (x+y)%mod;}//>=mod?x+y-mod:x+y;}
    void inc(int &x,int y){x=ad(x,y);}
    int mul(int x,int y){return (ll)x*y%mod;}
    void inc2(int &x,int y){x=mul(x,y);}
    int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
    }
    using namespace Modulo;
    namespace Miracle{
    const int N=400000+5;
    int n,d;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    int val[N];
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    bool vis[N];
    int pri[N],tot;
    int phi[N];
    int mindiv[N];
    int inv[N];
    int miu[N];
    void sieve(int n){
        phi[1]=1;
        miu[1]=1;
        for(reg i=2;i<=n;++i){
            if(!vis[i]){
                pri[++tot]=i;
                phi[i]=i-1;
                mindiv[i]=i;
                miu[i]=-1;
            }
            for(reg j=1;j<=tot;++j){
                if(i*pri[j]>n) break;
                vis[i*pri[j]]=1;
                mindiv[i*pri[j]]=pri[j];
                if(i%pri[j]==0){
                    phi[i*pri[j]]=phi[i]*pri[j];
                    miu[i*pri[j]]=0;
                    break;
                }
                phi[i*pri[j]]=phi[i]*(pri[j]-1);
                miu[i*pri[j]]=-miu[i];
            }
        }
    }
    int dfn[N],dfn2[N],dep[N];
    int a[2*N],ca,lg[2*N];
    int mx[2*N][19];
    int fr[N];
    
    
    int fa[N];
    int df;
    int mem[N],num;
    int div[N];
    ll con,ans,sum;
    int sta[N],top;
    bool cmp(int x,int y){
        return dfn[x]<dfn[y];
    }
    void dfs(int x){
        // cout<<" dfs "<<x<<" fa "<<fa[x]<<endl;
        dfn[x]=++df;
        a[++ca]=x;
        fr[x]=ca;
        dep[x]=dep[fa[x]]+1;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa[x]) continue;
            fa[y]=x;
            dfs(y);
            a[++ca]=x;
        }
        dfn2[x]=df;
    }
    int lca(int x,int y){
        if(x==y) return x;
        x=fr[x];y=fr[y];
        int len=y-x+1;
        int a=mx[x][lg[len]],b=mx[y-(1<<lg[len])+1][lg[len]];
        return dep[a]<dep[b]?a:b;
    }
    int f[N];
    void dp(int x,int fa){
        // cout<<" dp "<<x<<" "<<fa<<endl;
        if(x%d==0) f[x]=phi[x];
        else f[x]=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            dp(y,x);
            f[x]=ad(f[x],f[y]);
        }
        if(fa){
            ans=ad(ans,mul(mul(con,mul(f[x],ad(sum,mod-f[x]))),dep[x]-dep[fa]));
        }
    }
    int main(){
        rd(n);
        sieve(n);
        inv[1]=1;
        for(reg i=2;i<=n;++i){
            inv[i]=mul(mod-mod/i,inv[mod%i]);
        }
        for(reg i=1;i<=n;++i){
            rd(val[i]);
        }
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);
            x=val[x],y=val[y];
            add(x,y);add(y,x);
        }
        dfs(1);
        for(reg i=1;i<=2*n;++i){
            lg[i]=(i>>(lg[i-1]+1)?lg[i-1]+1:lg[i-1]);
        }
        // cout<<"ca "<<ca<<endl;
        // prt(a,1,ca);
        // prt(fr,1,n);
    
        for(reg i=1;i<=ca;++i){
            mx[i][0]=a[i];
        }
        for(reg j=1;j<=18;++j){
            for(reg i=1;i+(1<<j)-1<=ca;++i){
                mx[i][j]=(dep[mx[i][j-1]]>dep[mx[i+(1<<(j-1))][j-1]]?mx[i+(1<<(j-1))][j-1]:mx[i][j-1]);
                // cout<<" mx i j "<<i<<" "<<j<<" : "<<mx[i][j]<<endl;
            }
        }
    
        cnt=0;tot=0;
        memset(hd,0,sizeof hd);
        for(d=1;d<=n;++d){
            // cout<<"--------d "<<d<<endl;
            if(!miu[d]) continue;
            con=0;tot=0;
            sum=0;
            int lp=d;
            while(lp!=1){
                int pr=mindiv[lp];
                div[tot++]=pr;
                while(mindiv[lp]==pr) lp/=pr;
            }
            for(reg s=0;s<(1<<tot);++s){
                int now=1;
                for(reg i=0;i<tot;++i){
                    if(s&(1<<i)) now=mul(now,mul(div[i],inv[div[i]-1]));
                }
                // cout<<" now "<<now<<endl;
                if((tot-__builtin_popcount(s))&1){
                    con=ad(con,mod-now);
                }else con=ad(con,now);
            }
    
            // cout<<" con "<<con<<endl;
    
            cnt=0;tot=0,num=0;
            for(reg j=d;j<=n;j+=d){
                mem[++num]=j;
                sum=ad(sum,phi[j]);
            }
            sort(mem+1,mem+num+1,cmp);
            int od=num;
            for(reg i=1;i<od;++i){
                int anc=lca(mem[i],mem[i+1]);
                // cout<<mem[i]<<" "<<mem[i+1]<<" anc "<<anc<<endl;
                mem[++num]=anc;
            }
            sort(mem+1,mem+num+1,cmp);
            top=0;
            mem[0]=0;
            for(reg i=1;i<=num;++i){
                if(mem[i]==mem[i-1]) continue;
                int x=mem[i];
                while(top&&!(dfn[sta[top]]<=dfn[x]&&dfn2[x]<=dfn2[sta[top]])) --top;
                if(top) {
                    add(sta[top],x);
                }
                sta[++top]=x;
            }
            // cout<<" pre "<<top<<" "<<num<<endl;
            dp(mem[1],0);
            // cout<<" over "<<endl;
            //clear
            for(reg i=1;i<=num;++i){
                hd[mem[i]]=0;f[mem[i]]=0;
            }
            cnt=0;
            // cout<<" ans "<<ans<<endl;
            // memset(hd,0,sizeof hd);
        }
        // cout<<" ans "<<ans<<endl;
        ll mom=mul(n,n-1);
        ans=mul(ans,2);
        ans=mul(ans,qm(mom));
        ot(ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */
  • 相关阅读:
    Azure SQL Database (1) 用户手册
    Windows Azure Web Site (17) Azure Web Site 固定公网IP地址
    MongoDB数据文件内部结构
    压缩 MongoDB 的数据文件
    服务器如何选择网络带宽(转)
    刀片服务器和磁盘阵列卡(RAID)技术---永和维护(转)
    Solr打分出错
    Solr添加SolrDocument报错
    解决Windows Git Bash中文乱码问题
    HAProxy的独门武器:ebtree
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10915045.html
Copyright © 2020-2023  润新知