首先赞一下题目, 好题

题意:

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.

英文自己看。 大概意思就是一棵树上每一个点i能够给一个L[i] ~ R[i]的值, 相邻的两个点的值要互质, 问每一个点的全部情况的值的和, mod 1000000007

大概思路就是枚举一个点, 然后枚举这个点上的值(i)。 然后求出这种情况有多少种(dp[i]), 那么这个点上的答案就是 dp[1] * 1 + dp[2] * 2 + dp[3] * 3 + .........

然后就是树形dp了, 转移方程就是 dp[i][j] =π{(∑{dp[t][k]
| gcd(j, k) == 1}) | i 和 t 相邻}

可是这样转移的复杂度是50 * 50000 * 50000, 就算15秒时限也会超时

所以我们能够考虑用不互质的来转移。

设s[i] = ∑dp[i][j]

那么转移方程就是   dp[i][j] =π{(s[i] - ∑{dp[t][k]
| gcd(j, k) != 1}) | i 和 t 相邻}

对于dp[i][j],我们能够把 j 质因数分解, 如果 j = p1^e1 * p2^e2 * p3^e3。 50000以内的数最多有6个不同的质因数;

然后我们记录一下 div[i][k] = ∑{ dp[i][j] | j 是 k 的倍数}, 这个能够nlogn的复杂度处理出来;

这样  ∑{dp[t][k] | gcd(j, k) != 1} = div[t][p1]
+ div[t][p2] + div[t][p3] - div[t][p1 * p2] - div[t][p1 * p3] - div[t][p2 * p3] + div[t][p1 * p2 * p3],
这样能够用容斥原理算了, 复杂度最多为2 ^ 6;

这样dp一次复杂度大概就是 50
* 50000 * (log50000 + 2^6);

要算50个点的话。
还是会超时;

可是这是一颗树。
对每一个点都dp一次的话算了非常多反复的东西, 所以我们不要每次都去所有dp一次, 比如算完i点的了, 要去算j点的, 如果i j相邻。 那么在dp数组中仅仅有i和j的值有变化。 我们就仅仅要再算这两个点的dp转移就够了。

很多其它细节请看代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <vector> using namespace std; typedef long long LL;
const int N = 50009;
const LL M = 1000000007; inline void addIt(int &a, int b)
{
a += b;
if(a >= M) a -= M;
} inline int sub(int a, int b)
{
a -= b;
if(a < 0) a += M;
if(a >= M) a -= M;
return a;
} struct Num
{
int p[11];
int allp;
}num[N]; struct Data
{
int dp[N], div[N], all;
}data[55], fb[55]; int L[55], R[55];
int ans[55];
int n;
vector<int> e[55];
bool vis[55];
int rcn, rcv; void print()
{
for(int i = 0; i < n; i++)
{
printf("i = %d\n", i);
for(int j = 0; j < 6; j++) printf("dp[%d] = %d\n", j, data[i].dp[j]);
}
} int rc(int i, int xs)
{
int t, r = 0;
for(; i < num[rcn].allp; i++)
{
if(xs * num[rcn].p[i] <= R[rcv]) t = data[rcv].div[xs * num[rcn].p[i]];
else t = 0;
//printf("***%d, t = %d\n", xs * num[rcn].p[i], t);
addIt(r, sub(t, rc(i + 1, xs * num[rcn].p[i])));
}
//printf("r = %d\n", r);
return r;
} void dfsTree(int pre, int now)
{
if(vis[now]) return;
vis[now] = true;
int i, siz = e[now].size();
for(i = 0; i < siz; i++) dfsTree(now, e[now][i]);
if(pre >= 0 && siz <= 1) for(i = L[now]; i <= R[now]; i++) data[now].dp[i] = 1;
else for(i = L[now]; i <= R[now]; i++)
{
data[now].dp[i] = 1;
for(int j = 0; j < siz; j++) if(e[now][j] != pre)
{
rcn = i;
rcv = e[now][j];
data[now].dp[i] = (LL)(data[now].dp[i]) * sub(data[e[now][j]].all, rc(0, 1)) % M;
}
}
data[now].all = 0;
for(i = 1; i <= R[now]; i++)
{
data[now].div[i] = 0;
for(int j = i; j <= R[now]; j += i) if(j >= L[now]) addIt(data[now].div[i], data[now].dp[j]);
if(i >= L[now]) addIt(data[now].all, data[now].dp[i]);
}
} void dfs(int pre, int now, int deep)
{
dfsTree(-1, now);
//if(now == 1) print();
int i, siz = e[now].size();
ans[now] = 0;
for(i = L[now]; i <= R[now]; i++) addIt(ans[now], (LL)data[now].dp[i] * i % M);
//fb[deep] = data[now];
//vis[now] = false;
for(i = 0; i < siz; i++) if(e[now][i] != pre)
{
vis[e[now][i]] = false;
fb[deep] = data[e[now][i]];
vis[now] = false;
dfs(now, e[now][i], deep + 1);
data[e[now][i]] = fb[deep];
vis[e[now][i]] = true;
}
} void init()
{
int i, j, k;
for(i = 0; i < N; i++) num[i].allp = 0;
for(i = 2; i < N; i++) if(num[i].allp == 0) for(j = i; j < N; j += i) num[j].p[num[j].allp++] = i;
} int main()
{
//freopen("13F.in", "r", stdin);
init();
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int i, j, k;
for(i = 0; i < n; i++)
{
scanf("%d", &L[i]);
}
for(i = 0; i < n; i++)
{
scanf("%d", &R[i]);
e[i].clear();
}
for(i = 0; i < n - 1; i++)
{
scanf("%d %d", &j, &k);
j--;
k--;
e[j].push_back(k);
e[k].push_back(j);
}
memset(vis, false, sizeof(vis));
memset(data, 0, sizeof(data));
dfsTree(-1, 0);
//print();
dfs(-1, 0, 0);
for(i = 0; i < n - 1; i++) printf("%d ", ans[i]); printf("%d\n", ans[i]);
}
return 0;
}

2014牡丹江 现场赛 F zoj 3824 Fiber-optic Network的更多相关文章

  1. zoj 3820(2014牡丹江现场赛B题)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5374 思路:题目的意思是求树上的两点,使得树上其余的点到其中一个点的 ...

  2. 2014 牡丹江现场赛 A.Average Score(zoj 3819) 解题报告

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5373 题目意思: 有两个class:A 和 B,Bob 在 Clas ...

  3. 2014 牡丹江现场赛 i题 (zoj 3827 Information Entropy)

    I - Information Entropy Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %l ...

  4. zoj 3827(2014牡丹江现场赛 I题 )

    套公式 Sample Input 33 bit25 25 50 //百分数7 nat1 2 4 8 16 32 3710 dit10 10 10 10 10 10 10 10 10 10Sample ...

  5. zoj 3819(2014牡丹江现场赛 A题 )

    题意:给出A班和B班的学生成绩,如果bob(A班的)在B班的话,两个班级的平均分都会涨.求bob成绩可能的最大,最小值. A班成绩平均值(不含BOB)>A班成绩平均值(含BOB) &&a ...

  6. 2014西安现场赛F题 UVALA 7040

    地址 题意:求在m种颜色中挑选k种颜色,给n个花朵涂色有几种方法. 分析:画图可以发现,基本的公式就是k ×(k-1)^(n-1).但这仅保证了相邻颜色不同,总颜色数不超过k种,并没有保证恰好出现k种 ...

  7. CF GYM100548 (相邻格子颜色不同的方案数 2014西安现场赛F题 容斥原理)

    n个格子排成一行,有m种颜色,问用恰好k种颜色进行染色,使得相邻格子颜色不同的方案数. integers n, m, k (1 ≤n, m ≤ 10^9, 1 ≤ k ≤ 10^6, k ≤ n, m ...

  8. ZOJ 3827 Information Entropy(数学题 牡丹江现场赛)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do? problemId=5381 Information Theory is one of t ...

  9. 【解题报告】牡丹江现场赛之ABDIK ZOJ 3819 3820 3822 3827 3829

    那天在机房做的同步赛,比现场赛要慢了一小时开始,直播那边已经可以看到榜了,所以上来就知道A和I是水题,当时机房电脑出了点问题,就慢了好几分钟,12分钟才A掉第一题... A.Average Score ...

随机推荐

  1. 排序算法C语言实现——冒泡排序

    /*冒泡O(n^2)*//*原理:    比较相邻的元素.如果第一个比第二个大,就交换他们两个.    对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数 ...

  2. 【C#】【数据结构】002-线性表:单链表

    C#数据结构:单链表 1.自定义单链表结构: 单链节点类 using System.Collections; using System.Collections.Generic; using Unity ...

  3. redis和memcached的优缺点及区别

    1. 使用redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持string,li ...

  4. python基础——17(面向对象)

    一.名称空间 名称空间有内置名称空间,全局名称空间,局部名称空间.它是用来存放名字与值对应关系的地方. test.py文件: num = 10 def fn(): print("fn run ...

  5. luogu3980 [NOI2008]志愿者招募

    神题,还不太清楚 #include <iostream> #include <cstring> #include <cstdio> #include <que ...

  6. PHP 页面跳转的三种方式

    第一种方式:header() header()函数的主要功能是将HTTP协议标头(header)输出到浏览器. 语法: void header ( string $string [, bool $re ...

  7. 【编程工具】Sublime Text3的安装和常用插件推荐

    本人刚刚学习 HTML,曾经上网找过一些编写 HTML 的软件,但感觉都不太好,经过三挑四选下,最终我决定选择 Sublime Text3 这款软件来作为学习工具,上网找到了许多实用的插件,在这里给大 ...

  8. arc和mrc混用

    arc项目中引用非arc代码   加上“-fno-objc-arc” 非arc项目中引用arc代码 加上“-fobjc-arc”

  9. 【Luogu】P3455Zip-Queries(莫比乌斯反演)

    题目链接 真是神TM莫比乌斯 首先来看一个神奇的结论:求gcd(x,y)==k的对数,其中1<=x<=n,1<=y<=m 等同于求gcd(x,y)==1的对数,其中1<= ...

  10. 源码分析 脱壳神器ZjDroid工作原理

    0. 神器ZjDroid Xposed框架的另外一个功能就是实现应用的简单脱壳,其实说是Xposed的作用其实也不是,主要是模块编写的好就可以了,主要是利用Xposed的牛逼Hook技术实现的,下面就 ...