题目大意:

给你一棵树,树上的点编号为\(1-n\)。选两个点\(i、j\),能得到的得分是\(\phi(a_i*a_j)*dis(i,j)\),其中\(dis(i,j)\)表示\(a\)到\(b\)的最短距离。求一次选择能得到的得分的期望


推式子

显然是求\(\frac{1}{n(n-1)} \sum\limits_{i=1}^n \sum\limits_{j=1}^n \phi(i*j)*dis(i,j)\)

有这样一个式子\(\phi(i*j)=\frac{\phi(i)*phi(j)*gcd(i,j)}{\phi(gcd(i,j))}\),于是按照套路莫比乌斯反演一波

令 \(p_{a_i}=i\)

原式=\(\frac{1}{n(n-1)} \sum\limits_{d=1}^n \sum\limits_{i=1}^{n/d} \sum\limits_{j=1}^{n/d} \frac{\phi(id)*\phi(jd)*d}{\phi(d)}*dis(p_{id},p_{jd})*[gcd(i,j)==1]\)

\(=\frac{1}{n(n-1)} \sum\limits_{d=1}^n \frac{d}{\phi(d)} \sum\limits_{i=1}^{n/d}\mu(i) \sum\limits_{j=1}^{n/di} \sum\limits_{k=1}^{n/di} \phi(ijd)*\phi(ikd)*dis(p_{ijd},p_{jkd})\)

令 \(T=id\)

原式=\(\frac{1}{n(n-1)} \sum\limits_{T=1}^n \sum\limits_{d|T} \frac{d\mu(T/d)}{\phi(d)} \sum\limits_{i=1}^{n/d} \sum\limits_{j=1}^{n/d} \phi(ijd)*\phi(ikd)*dis(p_{ijd},p_{jkd})\)

\(\sum\limits_{T=1}^n \sum\limits_{d|T} \frac{d\mu(T/d)}{\phi(d)}\)可以用\(O(NlnN)\)的时间跑出来(会线性求的大佬请评论告知一下小蒟蒻做法谢谢QAQ),问题是\(\sum\limits_{i=1}^{n/d} \sum\limits_{j=1}^{n/d} \phi(ijd)*\phi(ikd)*dis(p_{ijd},p_{jkd})\),这个可以建虚树保证时间复杂度,在虚树上\(dp\)就行了……吗?


大概是个乱搞?

因为我太菜看不懂大佬们的\(dp\)做法,于是自己乱搞了一下:

设虚树上所有点的点集为\(V\),虚树上点\(x\)的贡献为\(B_x\) . 可以发现当\(w_x\neq 0\)时,\(T|a_x\)

于是就要求:

\[\sum\limits_{i\in V}\sum\limits_{j\in V} B_i*B_j*dis(i,j)\]

把距离拆开

\(\sum\limits_{i\in V}\sum\limits_{j\in V} B_i*B_j*dep_i+B_i*B_j*dep_j-2*B_i*B_j*dep_{lca}\)

令\(A_i=B_i*dep_i\),\(sum=\sum\limits _{i \in V} B_i\),则有:

\(\sum\limits_{i\in V}\sum\limits_{j\in V} A_i*w_j+A_j*B_i*dep_j-2*B_i*B_j*dep_{lca}\)

\(=2\sum\limits_{i\in V}sum*A_i-2\sum\limits_{i\in V}\sum\limits_{j\in V} B_i*B_j*dep_{lca}\)

这样就可以枚举\(lca\),\(dfs\)一遍求得答案

详见代码:

#include <bits/stdc++.h>
#define N 200010
#define mod 1000000007ll
#define ll long long
using namespace std;

int p[N],n,tot,cnt,f[N][18],dep[N],son[N],st[N],top[N],dfn[N],fa[N],fr,pr[N],bb,sz[N],d[N];
ll phi[N],S[N],u[N],inv[N],w[N],sum[N],pre,ans,B[N];
int head[N],nxt[N],v[N];
bool vis[N];
vector<int>G[N];

void init(int n){
    phi[1]=u[1]=inv[1]=1;
    for(int i=2;i<=n;++i){
        inv[i]=(1ll*mod-mod/i)*inv[mod%i]%mod;
        if(!vis[i]) pr[++cnt]=i,phi[i]=i-1,u[i]=-1;
        for(int j=1;j<=cnt && i*pr[j]<=n;++j){
            vis[i*pr[j]]=1;
            if(i%pr[j]!=0){
                u[i*pr[j]]=-u[i];
                phi[i*pr[j]]=phi[i]*(pr[j]-1);
            } else{
                u[i*pr[j]]=0;
                phi[i*pr[j]]=phi[i]*pr[j];
                break;
            }
        }
    }
    for(int i=1;i<=n;++i)
        for(int j=i;j<=n;j+=i)
            (S[j]+=1ll*u[j/i]*i%mod*inv[phi[i]]%mod)%=mod,(S[j]+=mod)%=mod;
}

void dfs1(int x,int f){
    fa[x]=f,dep[x]=dep[f]+1,sz[x]=1;
    for(int i=0;i<G[x].size();++i){
        int to=G[x][i];
        if(to!=f){
            dfs1(to,x);
            if(sz[to]>sz[son[x]]) son[x]=to;
        }
    }
}
void dfs2(int x,int s){
    dfn[x]=++cnt,top[x]=s;
    if(!son[x]) return;
    dfs2(son[x],s);
    for(int i=0;i<G[x].size();++i){
        int to=G[x][i];
        if(!dfn[to]) dfs2(to,to);
    }
}
inline int lca(int x,int y){
    if(x==0 || y==0) return 0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) return x;
    else return y;
}

void add(int x,int y){ v[++bb]=y,nxt[bb]=head[x],head[x]=bb; }
bool cmp(const int &x,const int &y){ return dfn[x]<dfn[y]; }

void insert(int p){
    if(fr==1){ st[++fr]=p;return; }
    int ff=lca(p,st[fr]);
    if(ff==st[fr]){
        st[++fr]=p;
        return;
    }
    while(fr>1 && dfn[st[fr-1]]>=dfn[ff]) add(st[fr-1],st[fr]),fr--;
    if(ff!=st[fr]) add(ff,st[fr]),st[fr]=ff;
    st[++fr]=p;
}
void build(int num){
    ll tmp=0;
    sort(d+1,d+num+1,cmp);
    fr=0,st[++fr]=0;
    for(int i=1;i<=num;++i){
        insert(d[i]);
        (pre+=B[d[i]])%=mod;
    }
    for(int i=1;i<=num;++i)
        (tmp+=2ll*pre%mod*B[d[i]]%mod*dep[d[i]]%mod)%=mod;
    while(fr>1)
        add(st[fr-1],st[fr]),fr--;
    ans=tmp;

}

void dfs3(int x,int f){
    sum[x]=0;
    for(int i=head[x];i;i=nxt[i]){
        int to=v[i];
        if(v[i]!=f && v[i]){
            dfs3(v[i],x);
            (sum[x]+=sum[to])%=mod;
        }
    }
    if(vis[x]) (sum[x]+=B[x])%=mod;
    for(int i=head[x];i;i=nxt[i]){
        int to=v[i];
        if(v[i]!=f && v[i]){
            (ans-=sum[to]%mod*(sum[x]-sum[to]+mod)%mod*2ll%mod*dep[x]%mod)%=mod;
            (ans+=mod)%=mod;
        }
    }
    if(vis[x]){
        (ans-=2ll*B[x]%mod*sum[x]%mod*dep[x]%mod)%=mod;
        (ans+=mod)%=mod;
    }
    head[x]=0;
}

int main(){
    int x,y,i,j;ll qwq=0;
    scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%d",&x),p[x]=i;
    init(n);
    for(i=1;i<n;++i){
        scanf("%d%d",&x,&y);
        G[x].push_back(y),G[y].push_back(x);
    }
    dfs1(1,0);
    dfs2(1,1);
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;++i){
        pre=0,tot=0;bb=0;
        for(j=i;j<=n;j+=i) d[++tot]=p[j],B[d[tot]]=phi[j],vis[d[tot]]=1;
        build(tot);
        dfs3(0,-1);
        (qwq+=S[i]*ans%mod)%=mod;
        for(j=1;j<=tot;++j) vis[d[j]]=0,B[d[j]]=0,d[j]=0;
    }
    printf("%I64d",qwq*inv[n-1]%mod*inv[n]%mod);
} 

CF809E Surprise me!(莫比乌斯反演+Dp(乱搞?))的更多相关文章

  1. CF809E Surprise me! 莫比乌斯反演、虚树

    传送门 简化题意:给出一棵\(n\)个点的树,编号为\(1\)到\(n\),第\(i\)个点的点权为\(a_i\),保证序列\(a_i\)是一个\(1\)到\(n\)的排列,求 \[ \frac{1} ...

  2. Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2)(A.暴力,B.优先队列,C.dp乱搞)

    A. Carrot Cakes time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  3. 2016 10 28考试 dp 乱搞 树状数组

    2016 10 28 考试 时间 7:50 AM to 11:15 AM 下载链接: 试题 考试包 这次考试对自己的表现非常不满意!! T1看出来是dp题目,但是在考试过程中并没有推出转移方程,考虑了 ...

  4. BZOJ - 2500 树形DP乱搞

    题意:给出一棵树,两个给给的人在第\(i\)天会从节点\(i\)沿着最长路径走,求最长的连续天数\([L,R]\)使得\([L,R]\)为起点的最长路径极差不超过m 求\(1\)到\(n\)的最长路经 ...

  5. HZOJ 20190727 T2 单(树上dp+乱搞?+乱推式子?+dfs?)

    考试T2,考试时想到了40pts解法,即对于求b数组,随便瞎搞一下就oxxk,求a的话,很明显的高斯消元,但考试时不会打+没开double挂成10pts(我真sb),感觉考试策略还是不够成熟,而且感觉 ...

  6. Codeforces 809E Surprise me! [莫比乌斯反演]

    洛谷 Codeforces 非常套路的一道题,很适合我在陷入低谷时提升信心-- 思路 显然我们需要大力推式子. 设\(p_{a_i}=i\),则有 \[ \begin{align*} n(n-1)an ...

  7. [BZOJ4011][HNOI2015]落忆枫音-[dp乱搞+拓扑排序]

    Description 传送门 Solution 假如我们的图为DAG图,总方案数ans为每个点的入度In相乘(不算1号点).(等同于在每个点的入边选一条边,最后一定构成一棵树). 然而如果加了边x- ...

  8. [OpenJudge90][序列DP+乱搞]滑雪

    滑雪 总时间限制: 1000ms 内存限制: 65536kB [描述] Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次 ...

  9. [CSP-S模拟测试]:最小值(DP+乱搞)

    题目背景 $Maxtir$更喜欢序列的最小值. 题目传送门(内部题128) 输入格式 第一行输入一个正整数$n$和四个整数$A,B,C,D$. 第二行输入$n$个整数,第$i$个数表示$a_i$. 输 ...

随机推荐

  1. 解决ViewGroup不调用onDraw()的问题

    今天在做项目的时候自定义了一个View,继承了LinearLayout,结果,里面的onDraw()方法一直无法被调用. 后来发现ViewGroup是默认不调用onDraw()方法的. 原因我们暂且不 ...

  2. Centos 7 安装 ifconfig 管理命令

    1. 安装的需求背景 我们知道ifconfig 命令可以用于查看.配置.启用或禁用指定网络接口,如配置网卡的IP地址.掩码.广播地址.网关等,功能不可谓不丰富. 此命令的功能和windows系统的ip ...

  3. mssql sqlserver 使用sql脚本 清空所有数据库表数据的方法分享

    摘要: 下文讲述清空数据库中所有表信息的方法分享,如下所示: 实验环境:sql server 2008 实现思路: 1.禁用所有约束,外键 2.禁用所有触发器 3.删除表数据 4.开启触发器 5.开启 ...

  4. iOS 防止UIButton重复点击

    使用UIButton的enabled或userInteractionEnabled 使用UIButton的enabled属性, 在点击后, 禁止UIButton的交互, 直到完成指定任务之后再将其en ...

  5. AXI-Lite总线及其自定义IP核使用分析总结

    ZYNQ的优势在于通过高效的接口总线组成了ARM+FPGA的架构.我认为两者是互为底层的,当进行算法验证时,ARM端现有的硬件控制器和库函数可以很方便地连接外设,而不像FPGA设计那样完全写出接口时序 ...

  6. Zabbix监控USG6300防火墙及交换机

    1.登录防火墙直接在web上面配置SNMP,只读团体名.读写团体名.Trap接收主机.安全名,点击应用完成防火墙上面的SNMP配置,如果你的命令行敲得6,可以使用命令行敲,配置效果一样,交换机没有这么 ...

  7. SQLServer无法删除登录名'***',因为该用户当前正处于登录状态解决方法

    问题描述: sqlserver在删除登录名的时候提示删除失败 标题: Microsoft SQL Server Management Studio -------------------------- ...

  8. python:过滤字符串中的字母数字特殊符号

    今天遇到的字符串处理的问题,记录一下方便使用 str1 = input('请输入一个字符:') #初始化字符.数字.空格.特殊字符的计数 lowercase = 0 uppercase = 0 num ...

  9. hadoop dfs.datanode.du.reserved 预留空间配置方法

    对于datanode配置预留空间的方法 为:在hdfs-site.xml添加如下配置 <property> <name>dfs.datanode.du.reserved< ...

  10. 前端面试回顾---javascript的面向对象

    转:https://segmentfault.com/a/1190000011061136 前言 前一阵面试,过程中发现问到一些很基础的问题时候,自己并不能很流畅的回答出来.或者遇到一些基础知识的应用 ...