HDU4812 D tree 【点分治 + 乘法逆元】
D树
时间限制:10000/5000 MS(Java / Others)内存限制:102400/102400
K(Java / Others)
总共提交5400个已接受的提交1144
10 6 + 3)的乘积等于K?
你能帮助他们解决这个问题吗?
每个测试用例都以包含两个整数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之间的无向边。
欲了解更多信息,请参阅下面的示例输出。
5 60
2 5 2 3 3
1 2
1 3
2 4
2 5
5 2
2 5 2 3 3
1 2
1 3
2 4
2 5
3 4
没有解决方案暗示1.“请按字典顺序打印最小的一个”。是指:先按照第一个数字的大小进行比较,若第一个数字大小相同,则按照第二个数字大小进行比较,依次类别。 2.若出现栈溢出,推荐使用C ++语言提交,并通过以下方式扩栈:
#pragma comment(linker,“/ STACK:102400000,102400000”)
点分治
这种树上找路径问题最容易想到的就是点分治
点治的思想其实很简单,分别以每个点为根,找出所有经过根的路径更新答案
由于路径是一个二维的量,直接枚举是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存表时算上根
继续练习吧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 100005,maxm = 200005,INF = 1000000000;
const LL P = 1000003;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int N,K,V[maxn],Siz[maxn],F[maxn],vis[maxn],rt,sum,ansx,ansy;
LL Hash[P],tmp[maxn],d[maxn],id[maxn],inv[P],cnt = 0;
int head[maxn],nedge = 0;
struct EDGE{int to,next;}edge[maxm];
inline void build(int u,int v){
edge[nedge] = (EDGE){v,head[u]}; head[u] = nedge++;
edge[nedge] = (EDGE){u,head[v]}; head[v] = nedge++;
}
void getRT(int u,int fa){
int to; Siz[u] = 1; F[u] = 0;
Redge(u) if (!vis[to = edge[k].to] && to != fa){
getRT(to,u);
Siz[u] += Siz[to];
F[u] = max(F[u],Siz[to]);
}
F[u] = max(F[u],sum - Siz[u]);
if (F[u] < F[rt]) rt = u;
}
inline void query(int x,int u){
x = 1ll * inv[x] * K % P;
int v = Hash[x];
if (!v) return;
if (v < u) swap(u,v);
if (u < ansx || (u == ansx && v < ansy))
ansx = u,ansy = v;
}
void dfs(int u,int fa){
tmp[++cnt] = d[u]; id[cnt] = u; int to;
Redge(u) if (!vis[to = edge[k].to] && to != fa){
d[to] = 1ll * V[to] * d[u] % P;
dfs(to,u);
}
}
void solve(int u){
int to; vis[u] = true; Hash[V[u]] = u;
Redge(u) if (!vis[to = edge[k].to]){
cnt = 0; d[to] = V[to];
dfs(to,u);
REP(i,cnt) query(tmp[i],id[i]);
cnt = 0; d[to] = 1ll * V[to] * V[u] % P;
dfs(to,u);
REP(i,cnt) if (!Hash[tmp[i]] || Hash[tmp[i]] > id[i]) Hash[tmp[i]] = id[i];
}
Hash[V[u]] = 0;
Redge(u) if (!vis[to = edge[k].to]){
cnt = 0; d[to] = 1ll * V[to] * V[u] % P;
dfs(to,u);
REP(i,cnt) Hash[tmp[i]] = 0;
}
Redge(u) if (!vis[to = edge[k].to]){
sum = Siz[to]; F[rt = 0] = INF;
getRT(to,rt);
solve(rt);
}
}
void init(){
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head)); nedge = 0; ansx = ansy = INF;
REP(i,N) V[i] = RD() % P;
REP(i,N - 1) build(RD(),RD());
}
void INIT(){
inv[1] = 1;
for (int i = 2; i < P; i++){
inv[i] = ((P - P / i) * inv[P % i] % P + P) % P;
}
}
int main(){
INIT();
while (~scanf("%d%d",&N,&K)){
init();
F[rt = 0] = INF; sum = N;
getRT(1,rt);
solve(rt);
if (ansx == INF) printf("No solution\n");
else printf("%d %d\n",ansx,ansy);
}
return 0;
}
HDU4812 D tree 【点分治 + 乘法逆元】的更多相关文章
- [hdu4812]D Tree(点分治)
题意:问有多少条路径,符合路径上所有节点的权值乘积模1000003等于k. 解题关键:预处理阶乘逆元,然后通过hash和树形dp$O(1)$的判定乘积存在问题,注意此道题是如何处理路径保证不重复的,具 ...
- 【点分治】【乘法逆元】hdu4812 D Tree
思路比较裸,但是要把答案存到哈希表里面,这里需要一定技巧,否则会被K=1且点权全是1的数据卡飞.预处理乘法逆元.TLE了一天.换了种点分治的姿势…… #pragma comment(linker,&q ...
- HDU4812 D Tree(树的点分治)
题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所 ...
- HDU 4812 D Tree 树分治
题意: 给出一棵树,每个节点上有个权值.要找到一对字典序最小的点对\((u, v)(u < v)\),使得路径\(u \to v\)上所有节点权值的乘积模\(10^6 + 3\)的值为\(k\) ...
- Bzoj2154 Crash的数字表格 乘法逆元+莫比乌斯反演(TLE)
题意:求sigma{lcm(i,j)},1<=i<=n,1<=j<=m 不妨令n<=m 首先把lcm(i,j)转成i*j/gcd(i,j) 正解不会...总之最后化出来的 ...
- 51nod1256(乘法逆元)
题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1256 题意:中文题诶~ 思路: M, N 互质, 求满足 K ...
- 【板子】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 ...
- HDU 5651 计算回文串个数问题(有重复的全排列、乘法逆元、费马小定理)
原题: http://acm.hdu.edu.cn/showproblem.php?pid=5651 很容易看出来的是,如果一个字符串中,多于一个字母出现奇数次,则该字符串无法形成回文串,因为不能删减 ...
- Codeforces 543D Road Improvement(树形DP + 乘法逆元)
题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007. 不难联想到这题和H ...
随机推荐
- 【独家】K8S漏洞报告 | 近期bug fix解读&1.9.11主要bug fix汇总
*内容提要: 1. Kube-proxy长连接优雅断开机制及IPVS模式实现 2. 10/29--11/19 bug fix汇总分析 3. 1.9.11重要bug fix汇总 在本周的跟踪分析中,以1 ...
- 「暑期训练」「基础DP」免费馅饼(HDU-1176)
题意与分析 中文题就不讲题意了.我是真的菜,菜出声. 不妨思考一下,限制了我们决策的有哪些因素?一,所在的位置:二,所在的时间.还有吗?没有了,所以设dp[i][j]" role=" ...
- 阿里云中linux 下svn服务器安装
摘要: 安装步骤如下: 1.yum install subversion 2.输入rpm -ql subversion查看安装位置,如下图: 我们知道svn在bin目录下生成了几个二进制文件. 输 ...
- Windows运行机理——窗口句柄和消息
Windows运行机理这系列文章都是来至于<零基础学Qt4编程>——吴迪,个人觉得写得很好,所以进行了搬运和个人加工 现在我们将消息与句柄联系起来.假如有一个窗口,且拥有该窗口的一个句柄( ...
- Unity编辑器 - Rigidbody动力学Bake到AnimationClip
Unity编辑器 - Rigidbody动力学Bake到AnimationClip Unity文档移动平台优化部分提到Physics对CPU的消耗较大 将动力学的特效如破碎等Bake成动画也是优化性能 ...
- MySql优化浅析
优化点:合理的使用索引,可以大幅度提升sql查询效率,特别查询的表的数据量大的时候,效果明显.一.引言 公司的产品XX出行上线正式运营,随着数据量的变大,司机2000+,日订单1万+,注册乘客26W+ ...
- 2018(容斥定理 HDU6286)
2018 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- [精通Python自然语言处理] Ch1 - 将句子切分为单词
实验对比了一下三种切分方式: 1,2 : nltk.word_tokenize : 分离缩略词,(“Don't” =>'Do', "n't") 表句子切分的“,” &quo ...
- C struct中的位域 bitfield
C struct中的位域 bitfield 结构体的成员可以限制其位域,每个成员可以使用用比字节还小的取值范围,下面的结构体s1中,四个成员每个成员都是2bit的值(0~3),整个结构体占据的空间依然 ...
- Python3 条件与循环
1.条件控制 下面是一个简单的条件控制语句 s=input('Please input a str: ') if s=='python': print('I love python!') elif s ...