zoukankan      html  css  js  c++  java
  • [cf809E]Surprise me

    令$d=gcd(a_{i},a_{j})$,则$varphi(a_{i}a_{j})=frac{varphi(a_{i})varphi(a_{j})d}{varphi(d)}$(证明直接质因数分解即可)

    枚举gcd并莫比乌斯反演,可得为$sum_{T=1}^{n}sum_{d|T}frac{dmu(frac{T}{d})}{varphi(d)}sum_{i=1}^{frac{n}{T}}sum_{j=1}^{frac{n}{T}}varphi(iT)varphi(jT)dis(p_{iT},p_{jT})$(其中$p_{i}$表示$i$所在的位置,即$p_{a_{i}}=i$)

    对于$sum_{d|T}frac{dmu(frac{T}{d})}{varphi(d)}$,$o(nln n)$预处理即可,对于后半部分,先对所有$p_{iT}$并建出虚树,可以看作一棵$frac{n}{T}$个点的数,第$i$个点点权$v_{i}=varphi(iT)$,求$sum_{i=1}^{n'}sum_{j=1}^{n'}v_{i}v_{j}dis(i,j)$

    将距离拆为两部分,即$dis(i,j)=dep_{i}+dep_{j}-2dep_{lca(i,j)}$,前半部分即$2(sum_{i=1}^{n'}v_{i})(sum_{i=1}^{n'}v_{i}dep_{i})$,后半部分考虑枚举lca,即统计其不同的两棵子树中点权乘积和

    换言之,维护子树内点权和$sum_{k}$,那么即$sum_{son}(sum_{k}-sum_{son})sum_{son}$,再乘上$2dep_{k}$即可

    时间复杂度为$o(nln nlog_{2}n)$(建虚树排序),可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 200005
      4 #define mod 1000000007
      5 struct ji{
      6     int nex,to;
      7 }edge[N<<1];
      8 vector<int>v;
      9 int E,n,x,y,ans,p[N],vis[N],mu[N],phi[N],f[N],head[N],a[N],dfn[N],sh[N],st[N],sum[N],fa[N][21];
     10 bool cmp(int x,int y){
     11     return dfn[x]<dfn[y];
     12 }
     13 int ksm(int n,int m){
     14     if (!m)return 1;
     15     int s=ksm(n,m>>1);
     16     s=1LL*s*s%mod;
     17     if (m&1)s=1LL*s*n%mod;
     18     return s;
     19 }
     20 void add(int x,int y){
     21     edge[E].nex=head[x];
     22     edge[E].to=y;
     23     head[x]=E++;
     24 }
     25 int lca(int x,int y){
     26     if (sh[x]<sh[y])swap(x,y);
     27     for(int i=20;i>=0;i--)
     28         if (sh[fa[x][i]]>=sh[y])x=fa[x][i];
     29     if (x==y)return x;
     30     for(int i=20;i>=0;i--)
     31         if (fa[x][i]!=fa[y][i]){
     32             x=fa[x][i];
     33             y=fa[y][i];
     34         }
     35     return fa[x][0];
     36 }
     37 void dfs1(int k,int f,int s){
     38     dfn[k]=++x;
     39     sh[k]=s;
     40     fa[k][0]=f;
     41     for(int i=1;i<=20;i++)fa[k][i]=fa[fa[k][i-1]][i-1];
     42     for(int i=head[k];i!=-1;i=edge[i].nex)
     43         if (edge[i].to!=f)dfs1(edge[i].to,k,s+1);
     44 }
     45 int dfs2(int k){
     46     int ans=0;
     47     for(int i=head[k];i!=-1;i=edge[i].nex){
     48         ans+=dfs2(edge[i].to);
     49         ans=(ans+2LL*sum[edge[i].to]*sum[k]%mod*sh[k])%mod;
     50         sum[k]=(sum[k]+sum[edge[i].to])%mod;
     51         sum[edge[i].to]=0;
     52     }
     53     head[k]=-1;
     54     return ans;
     55 }
     56 int calc(int k){
     57     int s=0,ans=0;
     58     v.clear();
     59     for(int i=k;i<=n;i+=k){
     60         v.push_back(a[i]);
     61         s=(s+phi[i])%mod;
     62     }
     63     sort(v.begin(),v.end(),cmp);
     64     E=st[0]=0;
     65     if (v[0]!=1)st[++st[0]]=1;
     66     for(int i=0;i<v.size();i++){
     67         x=lca(v[i],st[st[0]]);
     68         while ((st[0]>1)&&(sh[x]<=sh[st[st[0]-1]])){
     69             add(st[st[0]-1],st[st[0]]);
     70             st[0]--;
     71         }
     72         if ((st[0])&&(st[st[0]]!=x)){
     73             add(x,st[st[0]--]);
     74             st[++st[0]]=x;
     75         }
     76         st[++st[0]]=v[i];
     77     }
     78     while (st[0]>1){
     79         add(st[st[0]-1],st[st[0]]);
     80         st[0]--;
     81     }
     82     sum[1]=0;
     83     for(int i=k;i<=n;i+=k){
     84         sum[a[i]]=phi[i];
     85         ans=(ans+1LL*sh[a[i]]*phi[i]%mod*(s-phi[i]+mod))%mod;
     86     }
     87     return 2LL*(ans-dfs2(1)+mod)%mod;
     88 }
     89 int main(){
     90     mu[1]=phi[1]=1;
     91     for(int i=2;i<N-4;i++){
     92         if (!vis[i]){
     93             p[++p[0]]=i;
     94             mu[i]=-1;
     95             phi[i]=i-1;
     96         }
     97         for(int j=1;(j<=p[0])&&(i*p[j]<N-4);j++){
     98             vis[i*p[j]]=1;
     99             if (i%p[j]){
    100                 mu[i*p[j]]=mu[i]*mu[p[j]];
    101                 phi[i*p[j]]=phi[i]*phi[p[j]];
    102             }
    103             else{
    104                 mu[i*p[j]]=0;
    105                 phi[i*p[j]]=phi[i]*p[j];
    106                 break;
    107             }
    108         }
    109     }
    110     for(int i=1;i<N-4;i++)
    111         for(int j=i;j<N-4;j+=i)f[j]=(f[j]+1LL*i*mu[j/i]%mod*ksm(phi[i],mod-2))%mod;
    112     scanf("%d",&n);
    113     for(int i=1;i<=n;i++){
    114         scanf("%d",&x);
    115         a[x]=i;
    116     }
    117     memset(head,-1,sizeof(head));
    118     for(int i=1;i<n;i++){
    119         scanf("%d%d",&x,&y);
    120         add(x,y);
    121         add(y,x);
    122     }
    123     x=0;
    124     dfs1(1,1,0);
    125     memset(head,-1,sizeof(head));
    126     for(int i=1;i<=n;i++)ans=(ans+1LL*f[i]*calc(i))%mod;
    127     printf("%lld",1LL*ksm(n,mod-2)*ksm(n-1,mod-2)%mod*ans%mod);
    128 } 
    View Code
  • 相关阅读:
    Qt中的角度转弧度
    Qt5鼠标事件及实例
    POJ 2239 Selecting Courses【最大匹配】
    POJ 1325 Machine Schedule【最小点覆盖】
    POJ 1469 COURSES【二分图最大匹配】
    POJ 1274 The Perfect Stall【二分图最大匹配】
    poj2226Muddy Fields【最小点覆盖(建图的思路比较好)】
    hdu4160Dolls【最小路径覆盖】
    hdu2444The Accomodation of Students【判断二分图+最大匹配】
    HLG1407Leyni的游戏【最小点权覆盖集】
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13915041.html
Copyright © 2011-2022 走看看