D树

时间限制:10000/5000 MS(Java / Others)内存限制:102400/102400
K(Java / Others)

总共提交5400个已接受的提交1144

问题描述
南京理工大学的操场上站着一棵高大的树。在树的每个分支上是一个整数(树可以被看作是一个有N个顶点的连通图,而每个分支可以被当作一个顶点)。今天,树下的学生正在考虑一个问题:我们可以在树上找到这样一个链,使链上所有整数(mod
10 6 + 3)的乘积等于K?

你能帮助他们解决这个问题吗?
 
输入
有几个测试用例,请处理,直到EOF。

每个测试用例都以包含两个整数N(1 <= N <= 10 5)和K(0 <= <<10 6 +
3)的行开始。下面一行包含n个数字v i(1 <= v i <10 6 +
3),其中vi表示顶点i上的整数。然后遵循N - 1行。每行包含两个整数x和y,表示顶点x和顶点y之间的无向边。
 
产量
对于每个测试用例,打印一个单行,其中包含两个整数a和b(其中a <b),表示链的两个端点。如果存在多个解决方案,请打印词典上最小的一个。如果没有解决方案,请打印“无解”(不含引号)。

欲了解更多信息,请参阅下面的示例输出。
 
示例输入
  1. 5 60
  2. 2 5 2 3 3
  3. 1 2
  4. 1 3
  5. 2 4
  6. 2 5
  7. 5 2
  8. 2 5 2 3 3
  9. 1 2
  10. 1 3
  11. 2 4
  12. 2 5
 
示例输出
  1. 3 4
  2. 没有解决方案
  3. 暗示
  4. 1.“请按字典顺序打印最小的一个”。是指:先按照第一个数字的大小进行比较,若第一个数字大小相同,则按照第二个数字大小进行比较,依次类别。
  5. 2.若出现栈溢出,推荐使用C ++语言提交,并通过以下方式扩栈:
  6. #pragma commentlinker,“/ STACK102400000,102400000”)
  7.  

点分治

这种树上找路径问题最容易想到的就是点分治

点治的思想其实很简单,分别以每个点为根,找出所有经过根的路径更新答案

由于路径是一个二维的量,直接枚举是O(n^2),而点分治通过固定一个根而使问题简化为一维O(n)

而由于树的性质,只要我们每次求出重心就可以保证最多只有logn层

总的复杂度就成了O(每一层操作复杂度 * logn)一般都是O(nlogn)或O(nlog^2n)

然而我点分治还是很生疏【我还是太弱了】

对于这道题,我们需要找到两条路径权值乘积取模为K

对于x * y ≡ K (mod P),可以化为x ≡ K/y (mod P)

所以我们只需开一个hash表存x的值,对于每个y,用K乘上y的逆元查表更新答案就好了

要注意的细节就是根节点也要算上,而且查找与更新的路径只能有一个经过根,也就是算y时不算上,而算x存表时算上根

继续练习吧

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define LL long long int
  6. #define REP(i,n) for (int i = 1; i <= (n); i++)
  7. #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
  8. using namespace std;
  9. const int maxn = 100005,maxm = 200005,INF = 1000000000;
  10. const LL P = 1000003;
  11. inline int RD(){
  12. int out = 0,flag = 1; char c = getchar();
  13. while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
  14. while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
  15. return out * flag;
  16. }
  17. int N,K,V[maxn],Siz[maxn],F[maxn],vis[maxn],rt,sum,ansx,ansy;
  18. LL Hash[P],tmp[maxn],d[maxn],id[maxn],inv[P],cnt = 0;
  19. int head[maxn],nedge = 0;
  20. struct EDGE{int to,next;}edge[maxm];
  21. inline void build(int u,int v){
  22. edge[nedge] = (EDGE){v,head[u]}; head[u] = nedge++;
  23. edge[nedge] = (EDGE){u,head[v]}; head[v] = nedge++;
  24. }
  25. void getRT(int u,int fa){
  26. int to; Siz[u] = 1; F[u] = 0;
  27. Redge(u) if (!vis[to = edge[k].to] && to != fa){
  28. getRT(to,u);
  29. Siz[u] += Siz[to];
  30. F[u] = max(F[u],Siz[to]);
  31. }
  32. F[u] = max(F[u],sum - Siz[u]);
  33. if (F[u] < F[rt]) rt = u;
  34. }
  35. inline void query(int x,int u){
  36. x = 1ll * inv[x] * K % P;
  37. int v = Hash[x];
  38. if (!v) return;
  39. if (v < u) swap(u,v);
  40. if (u < ansx || (u == ansx && v < ansy))
  41. ansx = u,ansy = v;
  42. }
  43. void dfs(int u,int fa){
  44. tmp[++cnt] = d[u]; id[cnt] = u; int to;
  45. Redge(u) if (!vis[to = edge[k].to] && to != fa){
  46. d[to] = 1ll * V[to] * d[u] % P;
  47. dfs(to,u);
  48. }
  49. }
  50. void solve(int u){
  51. int to; vis[u] = true; Hash[V[u]] = u;
  52. Redge(u) if (!vis[to = edge[k].to]){
  53. cnt = 0; d[to] = V[to];
  54. dfs(to,u);
  55. REP(i,cnt) query(tmp[i],id[i]);
  56. cnt = 0; d[to] = 1ll * V[to] * V[u] % P;
  57. dfs(to,u);
  58. REP(i,cnt) if (!Hash[tmp[i]] || Hash[tmp[i]] > id[i]) Hash[tmp[i]] = id[i];
  59. }
  60. Hash[V[u]] = 0;
  61. Redge(u) if (!vis[to = edge[k].to]){
  62. cnt = 0; d[to] = 1ll * V[to] * V[u] % P;
  63. dfs(to,u);
  64. REP(i,cnt) Hash[tmp[i]] = 0;
  65. }
  66. Redge(u) if (!vis[to = edge[k].to]){
  67. sum = Siz[to]; F[rt = 0] = INF;
  68. getRT(to,rt);
  69. solve(rt);
  70. }
  71. }
  72. void init(){
  73. memset(vis,0,sizeof(vis));
  74. memset(head,-1,sizeof(head)); nedge = 0; ansx = ansy = INF;
  75. REP(i,N) V[i] = RD() % P;
  76. REP(i,N - 1) build(RD(),RD());
  77. }
  78. void INIT(){
  79. inv[1] = 1;
  80. for (int i = 2; i < P; i++){
  81. inv[i] = ((P - P / i) * inv[P % i] % P + P) % P;
  82. }
  83. }
  84. int main(){
  85. INIT();
  86. while (~scanf("%d%d",&N,&K)){
  87. init();
  88. F[rt = 0] = INF; sum = N;
  89. getRT(1,rt);
  90. solve(rt);
  91. if (ansx == INF) printf("No solution\n");
  92. else printf("%d %d\n",ansx,ansy);
  93. }
  94. return 0;
  95. }

HDU4812 D tree 【点分治 + 乘法逆元】的更多相关文章

  1. [hdu4812]D Tree(点分治)

    题意:问有多少条路径,符合路径上所有节点的权值乘积模1000003等于k. 解题关键:预处理阶乘逆元,然后通过hash和树形dp$O(1)$的判定乘积存在问题,注意此道题是如何处理路径保证不重复的,具 ...

  2. 【点分治】【乘法逆元】hdu4812 D Tree

    思路比较裸,但是要把答案存到哈希表里面,这里需要一定技巧,否则会被K=1且点权全是1的数据卡飞.预处理乘法逆元.TLE了一天.换了种点分治的姿势…… #pragma comment(linker,&q ...

  3. HDU4812 D Tree(树的点分治)

    题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所 ...

  4. HDU 4812 D Tree 树分治

    题意: 给出一棵树,每个节点上有个权值.要找到一对字典序最小的点对\((u, v)(u < v)\),使得路径\(u \to v\)上所有节点权值的乘积模\(10^6 + 3\)的值为\(k\) ...

  5. Bzoj2154 Crash的数字表格 乘法逆元+莫比乌斯反演(TLE)

    题意:求sigma{lcm(i,j)},1<=i<=n,1<=j<=m 不妨令n<=m 首先把lcm(i,j)转成i*j/gcd(i,j) 正解不会...总之最后化出来的 ...

  6. 51nod1256(乘法逆元)

    题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1256 题意:中文题诶~ 思路: M, N 互质, 求满足 K ...

  7. 【板子】gcd、exgcd、乘法逆元、快速幂、快速乘、筛素数、快速求逆元、组合数

    1.gcd int gcd(int a,int b){ return b?gcd(b,a%b):a; } 2.扩展gcd )extend great common divisor ll exgcd(l ...

  8. HDU 5651 计算回文串个数问题(有重复的全排列、乘法逆元、费马小定理)

    原题: http://acm.hdu.edu.cn/showproblem.php?pid=5651 很容易看出来的是,如果一个字符串中,多于一个字母出现奇数次,则该字符串无法形成回文串,因为不能删减 ...

  9. Codeforces 543D Road Improvement(树形DP + 乘法逆元)

    题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007. 不难联想到这题和H ...

随机推荐

  1. 获取Chromium代码以及编译

    获取和编译Chromium必须自备梯子,最好是购买一个稳定的V*P*N,喜欢折腾的可以使用类似shadowsock的代理(需要设置google文档). 英文版教程文档可以参考这个界面,下面详细说Win ...

  2. Postman 高级用法指南

    Postman是一款强大的API接口测试工具,有许多不容易发现的好用的功能,下面简单介绍其中一部分功能.详细内容可以参考文档,官方还有视频教程,非常方便入手.后续本博客会持续提供一些Postman使用 ...

  3. 搜索二维矩阵 II

    描述 写出一个高效的算法来搜索m×n矩阵中的值,返回这个值出现的次数. 这个矩阵具有以下特性: 每行中的整数从左到右是排序的. 每一列的整数从上到下是排序的. 在每一行或每一列中没有重复的整数. 样例 ...

  4. Java学习 · 初识 IO流

    IO流   1. 原理与概念 a)     流 i.           流动,流向 ii.           从一端移动到另一端 源头到目的地 iii.           抽象.动态概念,是一连 ...

  5. CSS 之 选择器

    CSS的常见选择器 一.简单选择器 Simple Selectors 选择器 含义 * 通用元素选择器,匹配任何元素 E 标签选择器,匹配所有使用E标签的元素 .info class选择器,匹配所有c ...

  6. vista x64 vs2010 win32添加资源 未能完成操作解决办法

    非常痛苦的感觉,不能用vc6,msdn library也不好用,去2k3系统试了下,没有任何问题,无奈想重装系统了,但是太浪费时间,装了虚拟机也是vistax64的,安装之后正常... 卸载重新安装依 ...

  7. vector:动态数组

    vector是C++标准模板库中的部分内容,中文偶尔译作“容器”,但并不准确.它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存 ...

  8. 2019-1-7Xiaomi Mi5 刷全球版MIUI教程

    2019-1-7Xiaomi Mi5 刷全球版MIUI教程 mi5 教程 小书匠  欢迎走进zozo的学习之旅. 前言 固件下载 刷机 刷recovery,root 试用体验 其他参考 前言 机器是老 ...

  9. ASP.NET MVC中controller和view相互传值的方式

    ASP.NET MVC中Controller向view传值的方式: ViewBag.ViewData.TempData 单个值的传递 Json 匿名类型 ExpandoObject Cookie Vi ...

  10. 《Effective C#》快速笔记(五)- - C# 中的动态编程

    静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静态类型的语言,不过它加入了动态类型的语言特性,可以更高效地解决问题. 一. ...