Marjar University has decided to upgrade the infrastructure of school intranet by using fiber-optic technology. There are N buildings in the school. Each building will be installed with one router. These routers are connected by optical cables in such a way that there is exactly one path between any two routers.
Each router should be initialized with an operating frequency Fi before it starts to work. Due to the limitations of hardware and environment, the operating frequency should be an integer number within [Li, Ri]. In order to reduce the signal noise, the operating frequency of any two adjacent routers should be co-prime.
Edward is the headmaster of Marjar University. He is very interested in the number of different ways to initialize the operating frequency. Please write a program to help him! To make the report simple and neat, you only need to calculate the sum of Fi (modulo 1000000007) in all solutions for each router.
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
The first line contains one integer N (1 <= N <= 50). The next line contains N integers Li (1 <= Li <= 50000). Then, the following line contains N integers Ri (Li <= Ri <= 50000).
For the next N - 1 lines, each line contains two integers Xi and Yi. That means there is an optical cable connecting router Xi and router Yi (indexes are 1-based).
For each test case, output a line with N integers representing the sum of Fi (modulo 1000000007) in all solutions.
2 4 1 2 3 4 2 3 4 5 1 2 2 3 3 4 4 1 2 3 4 2 3 4 5 1 2 1 3 1 4
5 10 14 19 10 23 31 41
In the first sample test case, there are 4 ways to initialize the operating frequency:
Source: The 2014 ACM-ICPC Asia Mudanjiang Regional Contest
这是一道很让人印象深刻的题目0.0
写的也非常的丑(dfs了3次,用了好多个vector)
憋了一下午,还被喷了为何偷懒没写题(QAQ)
但是感觉非常锻炼能力。
先给出完整代码。
#include
#include
#include
#include
#include
#include
#include
#include
#include
总体思路:
预处理dfs0是将无根树转化为有根树,方便后续两次dfs的处理。
树上的dp嘛,有n-1条边,由于是无向边,在题目中的计算的时候是需要方向的(谁当谁的子树),那么实际上题目里就是要计算2*(n-1)条边,实际上就是每条边给两个方向。
第一次dfs,从1号点开始走,可以求出n-1条有向边的答案。
然后再通过再一次dfs2,求出剩下另外n-1条有向边的答案。
边的答案都求出来了,那么每个节点的每个取值的个数就是相应边的答案之积了。
.
细节思路:
先讲核心:
考虑这样一个孙子问题,给定一个整数区间[L,R](R<=50000),已知区间内的每个数都有一定的数量,每次给出一个查询整数a,现在求区间内与a互素的数的个数。(比如a=9,给定区间[2,4],告诉你2有5个(num[2]=5),3有10个(num[3]=10),4有100个(num[4]=100),那么答案就是5+100=105个)
方法可以用容斥原理做,首先素因子的个数只有几个(假设b个)。那么我们就可以通过预处理之后用容斥原理:2^b的复杂度去解决。
di[i]数组可以通过一个for循环在接近nlogn的复杂度内求出。
1:指的是i由奇数个j的素因子累乘而成的。
2:指的是i由偶数个j的素因子累乘而成的。
s[j]表示取j值的时候与区间不互素的个数。那么和j互素的个数=数字的总数-s[j]
然后这个问题解决了,窝们可以在第一次dfs的时候求出1号节点(根节点的答案)。
然后问题是如何再以较低的时间复杂度更新其他点?
再dfs2一次即可。这里我用的方法有求逆元。。虽然看上去并不是一个十分美的方法,目前也只会这种方法。
假定u的答案已经求好,对于u每个的v节点,窝们只需要除掉(指的是除法(这里通过求逆元))u->v的那条边的方案数,就可以逆转父子关系,再重新预处理求一下di数组和sum数组等等,就能算出v的答案了,以此类推。