Problem Statement

You are given an undirected tree with $N$ vertices.

Let us call the vertices Vertex $1$, Vertex $2$, $\ldots$, Vertex $N$. For each $1\leq i\leq N-1$, the $i$-th edge connects Vertex $U_i$ and Vertex $V_i$.

Additionally, each vertex is assigned a positive integer: Vertex $i$ is assigned $A_i$.

The cost between two distinct vertices $s$ and $t$, $C(s,t)$, is defined as follows.

Let $p_1(=s)$, $p_2$, $\ldots$, $p_k(=t)$ be the vertices of the simple path connecting Vertex $s$ and Vertex $t$, where $k$ is the number of vertices in the path (including the endpoints).

Then, let $C(s,t)=k\times \gcd (A_{p_1},A_{p_2},\ldots,A_{p_k})$,

where $\gcd (X_1,X_2,\ldots, X_k)$ denotes the greatest common divisor of $X_1,X_2,\ldots, X_k$.

Find $\displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^N C(i,j)$, modulo $998244353$.

Constraints

  • $2 \leq N \leq 10^5$
  • $1 \leq A_i\leq 10^5$
  • $1\leq U_i<V_i\leq N$
  • All values in input are integers.
  • The given graph is a tree.

Input

Input is given from Standard Input in the following format:

$N$
$A_1$ $A_2$ $\cdots$ $A_N$
$U_1$ $V_1$
$U_2$ $V_2$
$\vdots$
$U_{N-1}$ $V_{N-1}$

Output

Print $\displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^N C(i,j)$, modulo $998244353$.


Sample Input 1

4
24 30 28 7
1 2
1 3
3 4

Sample Output 1

47

There are edges directly connecting Vertex $1$ and $2$, Vertex $1$ and $3$, and Vertex $3$ and $4$.
Thus, the costs are computed as follows.

  • $C(1,2)=2\times \gcd(24,30)=12$
  • $C(1,3)=2\times \gcd(24,28)=8$
  • $C(1,4)=3\times \gcd(24,28,7)=3$
  • $C(2,3)=3\times \gcd(30,24,28)=6$
  • $C(2,4)=4\times \gcd(30,24,28,7)=4$
  • $C(3,4)=2\times \gcd(28,7)=14$

Thus, the sought value is $\displaystyle\sum_{i=1}^{3}\sum_{j=i+1}^4 C(i,j)=(12+8+3)+(6+4)+14=47$ modulo $998244353$, which is $47$.


Sample Input 2

10
180 168 120 144 192 200 198 160 156 150
1 2
2 3
2 4
2 5
5 6
4 7
7 8
7 9
9 10

Sample Output 2

1184

两个东西乘起来,很不好算。我们尝试拆开来算,就是枚举一个,求另一个的和。

路径数量和 gcd,看起来枚举gcd更容易。为了方便,设一个边 \((u,v)\) 的边权为 \(\gcd(a_u,a_v)\),这样也好加边。设现在枚举,令 \(k\) 为枚举到的最小公因数,一个很自然的想法就是把所有 \(a\) 为 \(k\) 的倍数的边拎出来,组成一棵树,然后跑一个 dp。考虑一条边 \((u,v,w)\),那么 \(w\) 的因数个数就是他会被计算的次数,因数个数 \(\sqrt{w}\) 个,所以如果能保证dp和建树是严格 \(O(n)\),最终复杂度是 \(O(n\sqrt{n})\)

先来看一下怎么dp。现在给出一棵树,我们要求所有路径长度之和。首先可以每个连通块单独考虑。定义 \(dp_i\) 为所有树上以 \(i\) 为端点的路径之和, \(c_i\) 为 \(i\) 为根的子树大小。那么 \(dp_v\) 转移到 \(dp_i\) 时,共有 \(c_v\) 个路径,他们长度全部增加1。算最终答案时,目前的 \(dp_i\) 会有多 \(c_v\) 个, \(dp_v\) 会多目前的 \(c_i\) 个。

但是我们发现这样算出来的答案不完全对。因为我们并不能保证这些路径的 \(\gcd\) 为 \(k\),只能保证他是 \(k\) 的倍数。我们可以用筛法处理出一个容斥系数。因为我在算 \(k\) 的答案一定算了 \(2k\) 的答案,在 \(2k\) 时容斥系数要减去那么多。

总复杂度 \(O(n\sqrt{n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,P=998244353;
int n,a[N],u[N],vis[N],e_num,hd[N],ret,ans,c[N],dp[N],p[N],fp[N],v[N];
struct edge{
int v,nxt;
}e[N<<1];
vector<int>g[N],f[N];
void add_edge(int u,int v)
{
e[++e_num]=(edge){v,hd[u]};
hd[u]=e_num;
}
int gcd(int x,int y)
{
if(!y)
return x;
return gcd(y,x%y);
}
void dfs(int x,int y)
{
// printf("%d %d\n",x,y);
vis[x]=0;
dp[x]=c[x]=1;
fp[x]=0;
for(int i=hd[x];i;i=e[i].nxt)
{
if(e[i].v==y)
continue;
dfs(e[i].v,x);
int ac=c[x],ad=dp[x];
int bc=c[e[i].v],bd=dp[e[i].v];
(fp[x]+=(1LL*ad*bc%P+1LL*ac*bd%P)%P)%=P;
(fp[x]+=fp[e[i].v])%=P;
(dp[x]+=(bc+bd)%P)%=P;
(c[x]+=bc)%=P;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
for(int i=1;i<N;i++)
for(int j=1;j*i<N;j++)
g[i*j].push_back(i);
for(int i=1;i<n;i++)
{
scanf("%d%d",u+i,v+i);
int w=gcd(a[u[i]],a[v[i]]);
for(int j=0;j<g[w].size();j++)
f[g[w][j]].push_back(i);
}
for(int i=1;i<N;i++)
{
p[i]+=i;
for(int j=2;1LL*j*i<N;j++)
p[j*i]-=p[i];
e_num=0;
for(int j=0;j<f[i].size();j++)
{
int x=u[f[i][j]],y=v[f[i][j]];
add_edge(x,y);
add_edge(y,x);
vis[x]=vis[y]=1;
}
for(int j=0;j<f[i].size();j++)
{
int x=u[f[i][j]];
if(vis[x])
{
dfs(x,0);
(ans+=(1LL*fp[x]%P*p[i]%P))%=P;
}
}
for(int j=0;j<f[i].size();j++)
{
int x=u[f[i][j]],y=v[f[i][j]];
hd[x]=hd[y]=0;
}
// for(int i=1;i<=n;i++)
// printf("%d ",fp[i]);
// putchar('\n');
}
printf("%d",ans);
}

[ABC248G] GCD cost on the tree的更多相关文章

  1. Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】

    传送门:http://codeforces.com/contest/1092/problem/F F. Tree with Maximum Cost time limit per test 2 sec ...

  2. CF1092 --- Tree with Maximum Cost

    CF1324 --- Maximum White Subtree 题干 You are given a tree consisting exactly of \(n\) vertices. Tree ...

  3. POJ3013 Big Christmas Tree[转换 最短路]

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23387   Accepted: 5 ...

  4. Color a Tree[HDU1055]

    Color a Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  5. poj 3013 Big Christmas Tree (最短路径Dijsktra) -- 第一次用优先队列写Dijsktra

    http://poj.org/problem?id=3013 Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total S ...

  6. poj 3013 Big Christmas Tree

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 20974   Accepted: 4 ...

  7. Big Christmas Tree(poj-3013)最短路

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 25823   Accepted: 5 ...

  8. hdu-3071 Gcd & Lcm game---质因数分解+状态压缩+线段树

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3071 题目大意: 给定一个长度为n的序列m次操作,操作的种类一共有三种 查询 L :查询一个区间的所 ...

  9. HDU 2196 Computer 树形DP 经典题

    给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权, ...

  10. HDU 5861 Road (线段树)

    Road 题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5861 Description There are n villages alo ...

随机推荐

  1. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-12-playwright操作iframe-中篇

    1.简介 按照计划今天就要用实际的例子进行iframe自动化测试.经过宏哥长时间的查找,终于找到了一个含有iframe的网页(QQ邮箱和163邮箱),别的邮箱宏哥就没有细看了.所以今天这一篇的主要内容 ...

  2. LeetCode952三部曲之二:小幅度优化(137ms -> 122ms,超39% -> 超51%)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<LeetCode952三部曲& ...

  3. LSTM推导

    LSTM推导 forward propagation def lstm_cell_forward(xt, a_prev, c_prev, parameters): """ ...

  4. Python 搭建 FastAPI 项目

    一般网上的文章都是以脚本的方式写Demor的,没找到自己想要的那种项目结构型的示例(类似Java SpringBoot 创建 Model,通过 pom 进行关联配置的那种) 看了一些源码,再结合自己的 ...

  5. 如何创建集成 LSP 支持多语言的 Web 代码编辑器

    对于一个云开发平台来说,一个好的 Web IDE 能很大程度地提高用户的编码体验,而一个 Web IDE 的一个重要组成部分就是代码编辑器. 目前有着多款 web 上的代码编辑器可供选择,比如 Ace ...

  6. ES 2023新特性速解

    ES 2023新特性速解 一.新增数组方法 操作数组的方法 Array.prototype.toSorted(compareFn) //返回一个新数组,其中元素按升序排序,而不改变原始数组. Arra ...

  7. Python面向对象——1、什么是异常 2、为何处理异常 3、如何处理异常? 4、何时使用异常处理 网络编程的一些预备知识

    文章目录 异常 1.什么是异常 2.为何处理异常 3.如何处理异常? 4.何时使用异常处理 网络编程的一些预备知识 异常 1.什么是异常 异常是程序发生错误的信号.程序一旦出现错误,便会产生一个异常, ...

  8. Factors 分解质因数

    package com.yourself.yours; import java.util.Scanner; /** ****************************************** ...

  9. 轻松掌握组件启动之Redis集群扩展秘籍:轻松扩容与缩容,释放高性能潜能

    扩展集群操作 扩容 在我们原始的集群基础上,我们决定增加一台主节点(8007)和一台从节点(8008),这样新增的节点将会在下图中以虚线框的形式显示在集群中. 1: 首先,在 /usr/local/r ...

  10. SpringBoot如何缓存方法返回值?

    目录 Why? HowDo annotation MethodCache MethodCacheAspect controller SpringCache EnableCaching Cacheabl ...