• CF809E Surprise me!


    题解:

    一道很套路的题目

    首先一个结论

    $phi(xy)=frac{phi(x)*phi(y)*gcd(x,y)}{phi(gcd(x,y))}$

    这个按照$phi$的定义很容易知道

    然后我们可以枚举gcd,很套路的可以莫比乌斯反演

    然后变成给出k个点,求他们$phi(x)*phi(y)*dis(x,y)$

    考虑所以gcd的点数为$frac{n}{1}+frac{n}{2}+frac{n}{3}$=$nlogn$

    于是我们需要一个与点数相关的算法

    考虑虚树

    之后有两种办法解决$phi(x)*phi(y)*dis(x,y)$

    一种是考虑一个节点和它儿子节点的关系,那么就处理一下子树信息就行了

    一种是把$dis(x,y)$写成$dis(x)+dis(y)-2*dis(lca(x,y))$然后dp一下 

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define ll long long
    const int N=5e5;
    const int mo=1e9+7;
    int a[N],head[N],dfn[N],cnt,p[N],pos[N],q[N],bz[20][N],dep[N];
    int f[N],phi[N],pri[N],prinum,ispri[N],n,l,miu[N],inv2;
    bool tt[N];
    struct re{
      int a,b,c;
    }e[N*2];
    int fsp(int x,int y)
    {
      ll ans=1;
      while (y)
      {
        if (y&1) ans=ans*x%mo;
        x=1ll*x*x%mo; y>>=1; 
      }
      return ans;
    }
    IL void plu(int &x,int y)
    {
      x=(x+y)%mo;
    }
    IL void arr(int x,int y)
    {
      e[++l].a=head[x];
      e[l].b=y;
      head[x]=l;
    }
    void dfs(int x,int y)
    {
      dfn[x]=++cnt; bz[0][x]=y; dep[x]=dep[y]+1;
      for (rint u=head[x];u;u=e[u].a)
      {
        int v=e[u].b;
        if (v!=y) dfs(v,x);
      }
    }
    bool cmp(int x,int y)
    {
      return dfn[x]<dfn[y];
    }
    int lca(int x,int y)
    {
      if (dep[x]<dep[y]) swap(x,y);
      dep(i,19,0) if (dep[bz[i][x]]>=dep[y]) x=bz[i][x];
      if (x==y) return x;
      dep(i,19,0) if (bz[i][x]!=bz[i][y]) x=bz[i][x],y=bz[i][y];
      return bz[0][x];
    }
    ll pp;
    struct E{
      int l,head[N],ans[N];
      re e[N*2];
      IL void arr(int x,int y)
      {
        e[++l].a=head[x];
        e[l].b=y;
        e[l].c=x;
        head[x]=l;
      }
      IL void clear()
      {
        rep(i,1,l) head[e[i].c]=0;
        l=0;
      }
      void dfs(int x)
      {
        ans[x]=phi[a[x]];
        if (!tt[x])
        {
          ans[x]=0;
        }
        ll ans2=0;
        for (rint u=head[x];u;u=e[u].a)
        {
          int v=e[u].b;
          dfs(v);
          ans[x]=(ans[x]+ans[v])%mo; 
          ans2+=1ll*ans[v]*ans[v];
        }
        ans2=(1ll*ans[x]*ans[x]-ans2)%mo;
        pp=(pp+2*dep[x]*ans2)%mo;
      }
    }E;
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      ios::sync_with_stdio(false);
      cin>>n;
      rep(i,1,n) cin>>a[i],pos[a[i]]=i;
      rep(i,1,n-1)
      {
        int x,y;
        cin>>x>>y;
        arr(x,y); arr(y,x);
      }
      dfs(1,0);
      rep(i,1,19)
        rep(j,1,n)
          bz[i][j]=bz[i-1][bz[i-1][j]];
      miu[1]=1; phi[1]=1;
      rep(i,2,n)
      {
        if (!ispri[i]) {pri[++prinum]=i; miu[i]=-1; phi[i]=i-1;}
        for (int j=1;j<=prinum&&pri[j]*i<=n;j++)
        {
          ispri[i*pri[j]]=1;
          if (i%pri[j]==0)
          {
            miu[i*pri[j]]=0;
            phi[i*pri[j]]=phi[i]*pri[j];
            break;
          } else miu[i*pri[j]]=-miu[i],phi[i*pri[j]]=phi[i]*(pri[j]-1);
        }
      }
      rep(i,1,n)
      {
        int num=0;
        int ans=0;
        ll ans2=0;
        for (int j=1;j*i<=n;j++) p[++num]=pos[i*j],plu(ans,phi[i*j]);
        rep(j,1,num) ans2=(ans2+1ll*phi[i*j]*dep[p[j]])%mo;
        ans2=2ll*ans2*ans%mo; 
        sort(p+1,p+num+1,cmp);
        rep(i,1,num) tt[p[i]]=1;
        int h=1,t=1; q[h]=1;
        rep(i,1,num)
        {
          while (h<t&&dep[lca(p[i],q[t])]<=dep[q[t-1]])
          {
            E.arr(q[t-1],q[t]); t--;
          }
          int k=lca(p[i],q[t]);
          if (k!=q[t])
          {
            E.arr(k,q[t]); q[t]=k;
          }
          if (q[t]!=p[i]) q[++t]=p[i];
        }
        while (h<t)
        {
          E.arr(q[t-1],q[t]); t--;
        }
        pp=0;
        E.dfs(1);
        ans2=((ans2-pp)%mo+mo)%mo;
        f[i]=ans2;
        E.clear();
        rep(i,1,num) tt[p[i]]=0; 
      }
      ll ans2=0;
      rep(k,1,n)
      {
         int ans=0;
         for (int j=1;j*k<=n;j++)
         {
            plu(ans,miu[j]*f[j*k]);
         }
         ans2=(ans2+1ll*k*ans%mo*fsp(phi[k],mo-2))%mo;
      }
      cout<<ans2*fsp(n,mo-2)%mo*fsp(n-1,mo-2)%mo<<endl;
      return 0;
    }
  • 相关阅读:
    接口和抽象的区别
    继承-子父类中成员方法特点
    基本类型和引用类型作为参数传递
    大三寒假生活6
    大三寒假生活5
    大三寒假生活4
    大三寒假生活3
    大三寒假生活2
    大三寒假生活指导
    ajax实现文本框的联想功能
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10356921.html
Copyright © 2020-2023  润新知