[ABC248G] GCD cost on the tree
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的更多相关文章
- 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 ...
- CF1092 --- Tree with Maximum Cost
CF1324 --- Maximum White Subtree 题干 You are given a tree consisting exactly of \(n\) vertices. Tree ...
- POJ3013 Big Christmas Tree[转换 最短路]
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 23387 Accepted: 5 ...
- Color a Tree[HDU1055]
Color a Tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- poj 3013 Big Christmas Tree (最短路径Dijsktra) -- 第一次用优先队列写Dijsktra
http://poj.org/problem?id=3013 Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total S ...
- poj 3013 Big Christmas Tree
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 20974 Accepted: 4 ...
- Big Christmas Tree(poj-3013)最短路
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 25823 Accepted: 5 ...
- hdu-3071 Gcd & Lcm game---质因数分解+状态压缩+线段树
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3071 题目大意: 给定一个长度为n的序列m次操作,操作的种类一共有三种 查询 L :查询一个区间的所 ...
- HDU 2196 Computer 树形DP 经典题
给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权, ...
- HDU 5861 Road (线段树)
Road 题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5861 Description There are n villages alo ...
随机推荐
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-12-playwright操作iframe-中篇
1.简介 按照计划今天就要用实际的例子进行iframe自动化测试.经过宏哥长时间的查找,终于找到了一个含有iframe的网页(QQ邮箱和163邮箱),别的邮箱宏哥就没有细看了.所以今天这一篇的主要内容 ...
- LeetCode952三部曲之二:小幅度优化(137ms -> 122ms,超39% -> 超51%)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<LeetCode952三部曲& ...
- LSTM推导
LSTM推导 forward propagation def lstm_cell_forward(xt, a_prev, c_prev, parameters): """ ...
- Python 搭建 FastAPI 项目
一般网上的文章都是以脚本的方式写Demor的,没找到自己想要的那种项目结构型的示例(类似Java SpringBoot 创建 Model,通过 pom 进行关联配置的那种) 看了一些源码,再结合自己的 ...
- 如何创建集成 LSP 支持多语言的 Web 代码编辑器
对于一个云开发平台来说,一个好的 Web IDE 能很大程度地提高用户的编码体验,而一个 Web IDE 的一个重要组成部分就是代码编辑器. 目前有着多款 web 上的代码编辑器可供选择,比如 Ace ...
- ES 2023新特性速解
ES 2023新特性速解 一.新增数组方法 操作数组的方法 Array.prototype.toSorted(compareFn) //返回一个新数组,其中元素按升序排序,而不改变原始数组. Arra ...
- Python面向对象——1、什么是异常 2、为何处理异常 3、如何处理异常? 4、何时使用异常处理 网络编程的一些预备知识
文章目录 异常 1.什么是异常 2.为何处理异常 3.如何处理异常? 4.何时使用异常处理 网络编程的一些预备知识 异常 1.什么是异常 异常是程序发生错误的信号.程序一旦出现错误,便会产生一个异常, ...
- Factors 分解质因数
package com.yourself.yours; import java.util.Scanner; /** ****************************************** ...
- 轻松掌握组件启动之Redis集群扩展秘籍:轻松扩容与缩容,释放高性能潜能
扩展集群操作 扩容 在我们原始的集群基础上,我们决定增加一台主节点(8007)和一台从节点(8008),这样新增的节点将会在下图中以虚线框的形式显示在集群中. 1: 首先,在 /usr/local/r ...
- SpringBoot如何缓存方法返回值?
目录 Why? HowDo annotation MethodCache MethodCacheAspect controller SpringCache EnableCaching Cacheabl ...