【Codeforces715C&716E】Digit Tree 数学 + 点分治
C. Digit Tree
ZS the Coder has a large tree. It can be represented as an undirected connected graph of n vertices numbered from 0 to n - 1 and n - 1edges between them. There is a single nonzero digit written on each edge.
One day, ZS the Coder was bored and decided to investigate some properties of the tree. He chose a positive integer M, which iscoprime to 10, i.e.
.
ZS consider an ordered pair of distinct vertices (u, v) interesting when if he would follow the shortest path from vertex u to vertex v and write down all the digits he encounters on his path in the same order, he will get a decimal representaion of an integer divisible by M.
Formally, ZS consider an ordered pair of distinct vertices (u, v) interesting if the following states true:
- Let a1 = u, a2, ..., ak = v be the sequence of vertices on the shortest path from u to v in the order of encountering them;
- Let di (1 ≤ i < k) be the digit written on the edge between vertices ai and ai + 1;
- The integer
is divisible by M.
Help ZS the Coder find the number of interesting pairs!
Input
The first line of the input contains two integers, n and M (2 ≤ n ≤ 100 000, 1 ≤ M ≤ 109,
) — the number of vertices and the number ZS has chosen respectively.
The next n - 1 lines contain three integers each. i-th of them contains ui, vi and wi, denoting an edge between vertices ui and vi with digit wi written on it (0 ≤ ui, vi < n, 1 ≤ wi ≤ 9).
Output
Print a single integer — the number of interesting (by ZS the Coder's consideration) pairs.
Examples
6 7
0 1 2
4 2 4
2 0 1
3 0 9
2 5 7
7
5 11
1 2 3
2 0 3
3 0 3
4 3 3
8
Note
In the first sample case, the interesting pairs are (0, 4), (1, 2), (1, 5), (3, 2), (2, 5), (5, 2), (3, 5). The numbers that are formed by these pairs are 14, 21, 217, 91, 7, 7, 917 respectively, which are all multiples of 7. Note that (2, 5) and (5, 2) are considered different.

In the second sample case, the interesting pairs are (4, 0), (0, 4), (3, 2), (2, 3), (0, 1), (1, 0), (4, 1), (1, 4), and 6 of these pairs give the number 33 while 2 of them give the number 3333, which are all multiples of 11.

Solution
一道比较好想好写的点分治
点分治显然,考虑如何计算复合的路径条数。
对于每个点我们维护两个值$Dig[x],Dig'[x]$,表示重心到这个点的路径组成的数,以及这个点到重心组成的数
这样对于一个点对$<u,v>$我们可以知道他们的$Dig[u],Dig[v],Dig'[u],Dig'[v]$,那么他们所组成的数就是$Dig'[u]*10^{k}+Dig[v]$
这个$k$我们发现,就相当于是$deep[u]$,知道这些就有思路搞了
题目的要求就是$Dig<u,v>mod M=0$也就可以转化成$Dig'[u]*10^{deep[u]}+Dig[v]\equiv 0(modM)$
然后整理一下就可以得到$Dig'[u]\equiv -Dig[v]*\frac{1}{10^{deep[u]}}$
然后用map存一下式子右边,对于一个点,它对答案的贡献就是hash表里的$Dig'[u]$的数量
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
#define LL long long
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 100010
int N,M;
map<LL,LL>hash;
LL ans;
namespace Math
{
LL power[MAXN],Inv[MAXN];
inline LL Gcd(LL a,LL b) {if (!b) return a; else return Gcd(b,a%b);}
inline void ExGcd(LL a,LL b,LL &x,LL &y) {if (!b) {x=,y=; return;} ExGcd(b,a%b,y,x); y-=(a/b)*x;}
inline LL inv(LL X) {LL x,y; ExGcd(X,M,x,y); return (x%M+M)%M;}
inline LL Pow(LL x,LL y) {LL re=; for (LL i=y; i; i>>=,x=x*x%M) if (i&) re=re*x%M; return re;}
}
using namespace Math;
namespace TreeDivide
{
struct EdgeNode{int next,to,val;}edge[MAXN<<];
int head[MAXN],cnt=;
inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].val=w;}
inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
int size[MAXN],f[MAXN],visit[MAXN],root,deep[MAXN],Sz;
LL Dig[MAXN];
inline void Getroot(int x,int last)
{
size[x]=,f[x]=;
for (int i=head[x]; i; i=edge[i].next)
if (!visit[edge[i].to] && edge[i].to!=last)
{
Getroot(edge[i].to,x);
size[x]+=size[edge[i].to];
f[x]=max(f[x],size[edge[i].to]);
}
f[x]=max(f[x],Sz-f[x]);
if (f[x]<f[root]) root=x;
}
inline void DFS(int now,int last)
{
LL D=(((M-Dig[now])+M)%M*Inv[deep[now]])%M; hash[D]++;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
deep[edge[i].to]=deep[now]+,
Dig[edge[i].to]=(Dig[now]*%M+edge[i].val)%M,
DFS(edge[i].to,now);
}
inline LL Get(int now,int last)
{
LL re=hash[Dig[now]];
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
Dig[edge[i].to]=(edge[i].val*power[deep[now]]%M+Dig[now])%M,
deep[edge[i].to]=deep[now]+,
re+=Get(edge[i].to,now);
return re;
}
inline void Divide(int now)
{
visit[now]=;
hash.clear(); hash[]--;
Dig[now]=0LL,deep[now]=;
DFS(now,);
ans+=Get(now,);
for (int i=head[now]; i; i=edge[i].next)
if (!visit[edge[i].to])
hash.clear(),hash[]--,
Dig[edge[i].to]=edge[i].val%M,deep[edge[i].to]=,
DFS(edge[i].to,now),
ans-=Get(edge[i].to,now);
for (int i=head[now]; i; i=edge[i].next)
if (!visit[edge[i].to])
Sz=size[edge[i].to],f[root=]=N,
Getroot(edge[i].to,now),Divide(root);
}
}
using namespace TreeDivide;
int main()
{
N=read(),M=read();
for (int x,y,z,i=; i<=N-; i++) x=read()+,y=read()+,z=read(),InsertEdge(x,y,z);
for (int i=; i<=N; i++) power[i]=Pow(,i),Inv[i]=inv(power[i]);
Sz=N; f[root=]=N+;
Getroot(,); Divide(root);
printf("%I64d\n",ans);
return ;
}
【Codeforces715C&716E】Digit Tree 数学 + 点分治的更多相关文章
- 【Codeforces 715C】Digit Tree(点分治)
Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...
- CF 716E. Digit Tree [点分治]
题意:一棵树,边上有一个个位数字,走一条路径会得到一个数字,求有多少路径得到的数字可以整除\(P\) 路径统计一般就是点分治了 \[ a*10^{deep} + b \ \equiv \pmod P\ ...
- 【题解】Digit Tree
[题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...
- Codeforces 716 E Digit Tree
E. Digit Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...
- hdu 4670 Cube number on a tree(点分治)
Cube number on a tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/ ...
- 『sumdiv 数学推导 分治』
sumdiv(POJ 1845) Description 给定两个自然数A和B,S为A^B的所有正整数约数和,编程输出S mod 9901的结果. Input Format 只有一行,两个用空格隔开的 ...
- 【POJ1741】Tree(点分治)
[POJ1741]Tree(点分治) 题面 Vjudge 题目大意: 求树中距离小于\(K\)的点对的数量 题解 完全不觉得点分治了.. 简直\(GG\),更别说动态点分治了... 于是来复习一下. ...
- CF716E Digit Tree 点分治
题意: 给出一个树,每条边上写了一个数字,给出一个P,求有多少条路径按顺序读出的数字可以被P整除.保证P与10互质. 分析: 统计满足限制的路径,我们首先就想到了点分治. 随后我们就需要考量,我们是否 ...
- [poj1741][tree] (树/点分治)
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
随机推荐
- iOS中的round/ceil/floorf函数略解
extern float ceilf(float); extern double ceil(double); extern long double ceill(long double); extern ...
- Hadoop系列教程<一>---Hadoop是什么呢?
Hadoop适合应用于大数据存储和大数据分析的应用,适合于服务器几千台到几万台的集群运行,支持PB级的存储容量.Hadoop典型应用有:搜索.日志处理.推荐系统.数据分析.视频图像分析.数据保存等.但 ...
- python-list tuple dict set
1:删除一个列表末尾的元素 pop方法 >>> a [1, 'Jack', 2, 3, 2] >>> a.pop() >>> a [1, 'Jac ...
- IoC容器Autofac(5) - Autofac在Asp.net MVC Filter中的应用
Autofac结合EF在MVC中的使用,上一篇IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源码)已经介绍了.但是只是MVC中Co ...
- SqlServer主键和外键
*主键 主键就是数据行的唯一标识.不会重复的列才能当主键.一个表可以没有主键,但是会非常难以处理,因此没有特殊理由表都要设定主键. *主键特点:1不能重复的列.2主键不能为null. *同名时如何处理 ...
- Linux下监控服务器状态命令——top
----------------------------------工作中常用的命令,来判断服务器状态是否正常------------------------------------- top命令作用 ...
- 在cmd和terminal怎么粘贴?
在osx, linux的terminal 以及windows的 cmd实现粘贴是coder经常要做的事,鼠标右键,下拉菜单中单击粘贴paste.但是这显得笨拙,及其不快捷.但是正常使用的command ...
- protobuf学习(1)-ubuntu14.04下protobuf2.6安装
1 下载protobuf https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz 2 进入 ...
- Fiddler进行模拟Post提交数据,总为null解决方式
Fiddler模拟post提交时总是为空,解决办法 如果是表单提交则要在header加上 ContentType:application/x-www-form-urlencoded 如果是要post提 ...
- java操作hdfs实例
环境:window7+eclipse+vmware虚拟机+搭建好的hadoop环境(master.slave01.slave02) 内容:主要是在windows环境下,利用eclipse如何来操作hd ...