Description

程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边。每条边上都有一个非零的数字。

一天,程序员 ZS 无聊,他决定研究一下这棵树的一些特性。他选择了一个十进制正整数 \(M\),\(\gcd(M,10)=1\)。

对于一对有序的不同的顶点 \((u, v)\),他沿着从顶点 \(u\) 到顶点 \(v\)的最短路径,按经过顺序写下他在路径上遇到的所有数字(从左往右写),如果得到一个可以被 \(M\) 整除的十进制整数,那么就认为 \((u,v)\) 是有趣的点对。

帮助程序员 ZS 得到有趣的对的数量。

Hint

  • \(1\le n\le 10^5\)
  • \(1\le m\le 10^9,\gcd(m, 10) = 1\)
  • \(1\le \text{边权} < 10\)

Solution

这种树上路径的统计问题基本都是 点分治,而点分治的重点和难点就是如何 统计经过分治中心的满足条件的路径的个数

这里采用 容斥法:即现分治中心为 \(s\),当前答案等于整个子树 \(s\) 的答案减去以 \(s\) 各个子结点为根的子树的答案。

考虑如何统计。

我们设有一条路径是 \(x\rightarrow y\),分治中心为 \(s\),路径 \(x\rightarrow s\) 对应的数字为 \(pd\),\(s\rightarrow y\) 对应 \(nd\),\(s\) 到 \(y\) 的距离为 \(l\)。

那么只有 \(pd \times 10^l + nd \equiv 0 \pmod m\) 成立时满足要求。

变形一下:\(pd \equiv -nd \times 10^{-l}\pmod m\)。

于是我们可以这样搞:把所有的 \(pd\) 用 map 存起来,记录一下个数,用 pair 数组把 \((nd, l)\) 记录下来。

导入所有了路径信息后,枚举 pair 数组,查找 map 中的元素配对即可。

预处理一下 \(10\) 的幂及其逆元的话,时间复杂度 \(O(n\log^2 n)\)。如果用 Hash Table 可以优化到理论 \(O(n\log n)\),但没什么必要。

Code

  1. /*
  2. * Author : _Wallace_
  3. * Source : https://www.cnblogs.com/-Wallace-/
  4. * Problem : Codeforces 715E Digit Tree
  5. */
  6. #include <cstdio>
  7. #include <map>
  8. #include <utility>
  9. #include <vector>
  10. using namespace std;
  11. const int N = 1e5 + 5;
  12. namespace Inv {
  13. void extgcd(long long a, long long b, long long& x, long long& y) {
  14. if (!b) x = 1, y = 0;
  15. else extgcd(b, a % b, y, x), y -= a / b * x;
  16. }
  17. inline long long get(long long b, long long p) {
  18. long long x, y;
  19. extgcd(b, p, x, y);
  20. x = (x % p + p) % p;
  21. return x;
  22. }
  23. }
  24. int n, m;
  25. long long p10[N], invp[N];
  26. long long ans;
  27. struct edge { int to, len; };
  28. vector<edge> G[N];
  29. int root;
  30. int maxp[N], size[N];
  31. bool centr[N];
  32. int getSize(int x, int f) {
  33. size[x] = 1;
  34. for (auto y : G[x])
  35. if (!centr[y.to] && y.to != f)
  36. size[x] += getSize(y.to, x);
  37. return size[x];
  38. }
  39. void getCentr(int x, int f, int t) {
  40. maxp[x] = 0;
  41. for (auto y : G[x])
  42. if (!centr[y.to] && y.to != f) {
  43. getCentr(y.to, x, t);
  44. maxp[x] = max(maxp[x], size[y.to]);
  45. }
  46. maxp[x] = max(maxp[x], t - size[x]);
  47. if (maxp[x] < maxp[root]) root = x;
  48. }
  49. vector<pair<long long, int> > dat;
  50. map<long long, int> cnt;
  51. void getData(int x, int f, long long pd, long long nd, int dep) {
  52. if (dep >= 0) cnt[pd]++, dat.push_back(make_pair(nd, dep));
  53. for (auto y : G[x]) {
  54. if(centr[y.to] || y.to == f) continue;
  55. long long tpd = (pd + y.len * p10[dep + 1] % m) % m;
  56. long long tnd = (nd * 10 % m + y.len) % m;
  57. getData(y.to, x, tpd, tnd, dep + 1);
  58. }
  59. }
  60. inline long long count(int x, int d) {
  61. long long ret = 0;
  62. cnt.clear(), dat.clear();
  63. if (d == 0) getData(x, 0, 0, 0, -1);
  64. else getData(x, 0, d % m, d % m, 0);
  65. for (auto p : dat) {
  66. long long t = ((-p.first * invp[p.second + 1] % m) + m) % m;
  67. if (cnt.count(t)) ret += cnt[t];
  68. if (d == 0 && p.first == 0) ++ret;
  69. }
  70. return ret + (d == 0 ? cnt[0] : 0);
  71. }
  72. void solve(int x) {
  73. maxp[root = 0] = N;
  74. getCentr(x, 0, getSize(x, 0));
  75. int s = root; centr[s] = true;
  76. for (auto y : G[s])
  77. if (!centr[y.to])
  78. solve(y.to);
  79. ans += count(s, 0);
  80. for (auto y : G[s])
  81. if (!centr[y.to])
  82. ans -= count(y.to, y.len);
  83. centr[s] = false;
  84. }
  85. signed main() {
  86. scanf("%d%d", &n, &m);
  87. for (register int i = 1; i < n; i++) {
  88. int u, v, l;
  89. scanf("%d%d%d", &u, &v, &l);
  90. ++u, ++v;
  91. G[u].push_back(edge{v, l});
  92. G[v].push_back(edge{u, l});
  93. }
  94. p10[0] = 1 % m;
  95. for (register int i = 1; i <= n; i++)
  96. p10[i] = p10[i - 1] * 10 % m;
  97. invp[n] = Inv::get(p10[n], m);
  98. for (register int i = n - 1; i; i--)
  99. invp[i] = invp[i + 1] * 10 % m;
  100. ans = 0, solve(1);
  101. printf("%lld\n", ans);
  102. return 0;
  103. }

【Codeforces 715C】Digit Tree(点分治)的更多相关文章

  1. [Codeforces 715C] Digit Tree

    [题目链接] https://codeforces.com/contest/715/problem/C [算法] 考虑点分治 一条路径(x , y)合法当且仅当 : d(x) * 10 ^ dep(x ...

  2. CF 716E. Digit Tree [点分治]

    题意:一棵树,边上有一个个位数字,走一条路径会得到一个数字,求有多少路径得到的数字可以整除\(P\) 路径统计一般就是点分治了 \[ a*10^{deep} + b \ \equiv \pmod P\ ...

  3. CF716E Digit Tree 点分治

    题意: 给出一个树,每条边上写了一个数字,给出一个P,求有多少条路径按顺序读出的数字可以被P整除.保证P与10互质. 分析: 统计满足限制的路径,我们首先就想到了点分治. 随后我们就需要考量,我们是否 ...

  4. 【Codeforces715C&716E】Digit Tree 数学 + 点分治

    C. Digit Tree time limit per test:3 seconds memory limit per test:256 megabytes input:standard input ...

  5. Codeforces 716 E Digit Tree

    E. Digit Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...

  6. 【题解】Digit Tree

    [题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...

  7. Problem - D - Codeforces Fix a Tree

    Problem - D - Codeforces  Fix a Tree 看完第一名的代码,顿然醒悟... 我可以把所有单独的点全部当成线,那么只有线和环. 如果全是线的话,直接线的条数-1,便是操作 ...

  8. Codeforces 1039D You Are Given a Tree [根号分治,整体二分,贪心]

    洛谷 Codeforces 根号分治真是妙啊. 思路 考虑对于单独的一个\(k\)如何计算答案. 与"赛道修建"非常相似,但那题要求边,这题要求点,所以更加简单. 在每一个点贪心地 ...

  9. 【CodeForces】914 E. Palindromes in a Tree 点分治

    [题目]E. Palindromes in a Tree [题意]给定一棵树,每个点都有一个a~t的字符,一条路径回文定义为路径上的字符存在一个排列构成回文串,求经过每个点的回文路径数.n<=2 ...

随机推荐

  1. C语言设计模式(应用)

    #ifndef QUEUE_H #define QUEUE_H #define QUEUE_SIZE 10 typedef struct queue { int buffer[QUEUE_SIZE]; ...

  2. 使用进程池模拟多进程爬取url获取数据,使用进程绑定的回调函数去处理数据

    1 # 使用requests请求网页,爬取网页的内容 2 3 # 模拟使用进程池模拟多进程爬取网页获取数据,使用进程绑定的回调函数去处理数据 4 5 import requests 6 from mu ...

  3. CTF-WEB-HCTF 2018 Warmup

    题目链接 攻防世界-Warmup 解题思路 [原题复现]HCTF 2018 Warmup(文件包含)

  4. 给力啊!这篇Spring Bean的依赖注入方式笔记总结真的到位,没见过写的这么细的

    1. Bean的依赖注入概念 依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现.在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是 ...

  5. 无论PC还是Mac,都能畅快地使用移动硬盘

    如果你拥有一台Mac设备,总会遇到尴尬的那一刻--你在Mac上用得好好的移动硬盘怎么都不能被PC识别到.又或者你朋友在PC上用得好好的移动硬盘,连上你的Mac后,Mac里的文件死活就是拷贝不进移动硬盘 ...

  6. 在线思维导图Ayoa可以用来梳理双十一优惠规则哦

    一年一度的双十一又要来了,小伙伴们是否准备好开始买买买了呢?今年双十一,遇上英雄联盟S10总决赛,1/4决赛苏宁对上京东也让这个"电商大战"产生了很多有趣的梗.当然在玩梗的同时,广 ...

  7. 用Camtasia来快速给录制的视频添加水印

    在日常生活中,视频的流行度越来越高,各种短视频的软件蜂拥上市,所以越来越多的人走上了自媒体的道路,在这条路上,谁的视频更加的精致,谁才能获得更多的关注度,相应的也能增加自己的人气. 但是在制作视频的过 ...

  8. 「LOJ 3153」 「JOI Open 2019」三级跳

    题面 LOJ 3153 solution 对于任意一对\(A,B\),若区间\([A,B]\)中存在一个数权值大于\(A\)或\(B\),则用这个数来替代\(A\)或\(B\)显然更优. 故只需要考虑 ...

  9. jmeter测试udp

    jemter本身不支持udp测试,需要下载安装第三方插件,或者下载一个插件管理器(下面那个蝴蝶一样的图标),里面有各种插件可以供你下载 下载链接:https://jmeter-plugins.org/ ...

  10. CF1156D 0-1-Tree

    路径考虑顺序. 显然合法的路径只有以下两种: 一段 \(0\) 加一段 \(1\) 或一段 \(1\) 加一段 \(0\). 全 \(0\) 或全 \(1\). 用并查集将边权为 \(0\) 和 \( ...