2014牡丹江 现场赛 F zoj 3824 Fiber-optic Network

首先赞一下题目, 好题

题意:

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 [LiRi]. 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;
}
时间: 2024-12-24 03:57:58

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

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

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5373 题目意思: 有两个class:A 和 B,Bob 在 Class A 里面.现在给出 Class A(n-1人) 和 Class B(m人) 所有人的分数,除了Bob,所以Class A 少了一个人.现在需要找出 Bob 最大可能的分数和最少可能的分数,使得他在Class A 里面拉低平均分,而在Class B 里面提高平均分. 由于数据量不大,所以可以暴力枚

2014西安现场赛F题 UVALA 7040

地址 题意:求在m种颜色中挑选k种颜色,给n个花朵涂色有几种方法. 分析:画图可以发现,基本的公式就是k ×(k-1)^(n-1).但这仅保证了相邻颜色不同,总颜色数不超过k种,并没有保证恰好出现k种颜色:接着就是一个容斥问题,上述计算方法中包含了只含有2.3.….(k-1)种颜色的情况,需要通过容斥原理去除.假设出现p (2 <= p <= k-1)种颜色,从k种颜色中选取p种进行涂色,方案数为C(k,p) × p × (p-1)^(n-1) :总的方案数就是C(m,k) × ( k × (

14牡丹江现场赛 D ZOJ 3822 Domination

Domination Time Limit: 8 Seconds      Memory Limit: 131072 KB      Special Judge Edward is the headmaster of Marjar University. He is enthusiastic about chess and often plays chess with his friends. What's more, he bought a large decorative chessboar

HDU 5131 Little Zu Chongzhi&#39;s Triangles (状压DP +2014广州现场赛)

题目链接:HDU 5131 Little Zu Chongzhi's Triangles 题意:给出一些线段,在其中选出3根组成三角形,问用这些线段组成的所有三角形的最大面积是多少. 7 3 4 5 3 4 5 90 两个三角形是(3,3,4),(5,5,4). 思路:N最大12,状态压缩,把所有可能组成的三角形存起来.A&B==0则说明A|B状态是有效的. 贪心也能过..为什么? AC代码: #include <stdio.h> #include <string.h> #

HDU 5131 Song Jiang&#39;s rank list (结构体+MAP,2014广州现场赛)

题目链接:HDU 5131 Song Jiang's rank list 题意:对给出的好汉按杀敌数从大到小排序,若相等,按字典序排.M个询问,询问名字输出对应的主排名和次排名.(排序之后)主排名是在该名字前比他杀敌数多的人的个数加1,次排名是该名字前和他杀敌数相等的人的个数加1,(也就是杀敌数相等,但是字典序比他小的人数加1). AC代码: #include <stdio.h> #include <string> #include <map> #include <

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

那天在机房做的同步赛,比现场赛要慢了一小时开始,直播那边已经可以看到榜了,所以上来就知道A和I是水题,当时机房电脑出了点问题,就慢了好几分钟,12分钟才A掉第一题... A.Average Score 题目大意:给定A序列和B序列,长度分别是n和m,告诉你A序列中的n-1个数和B序列的m个数,求剩下的那个A序列中的数满足:将这个数从A序列移除,然后添加到B序列,使得A序列的平均值变小,B序列的平均值变大.求这个数的取值范围(是整数) 解题思路:求出A序列剩下的n-1个数的平均值,和B序列的平均值

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

马上要去上海了,刷刷现场赛的题找找感觉~~~ 这题.......额,没什么好说的,太水.. ZOJ Problem Set - 3819 Average Score Time Limit: 2 Seconds      Memory Limit: 65536 KB Bob is a freshman in Marjar University. He is clever and diligent. However, he is not good at math, especially in Mat

2014ACM/ICPC亚洲区域赛牡丹江现场赛总结

不知道如何说起-- 感觉还没那个比赛的感觉呢?现在就结束了. 9号.10号的时候学校还评比国奖.励志奖啥的,因为要来比赛,所以那些事情队友的国奖不能答辩,自己的励志奖班里乱搞要投票,自己又不在,真是无语了--烦得要死,然后在这些事情还没处理好之前我们就这样10号中午从地大去北京站上火车了--那时真感觉这场带着这种心情来现场赛感觉要打铁了-- 然后10号晚上队友的国奖让琦神帮答辩完了,得国奖无疑了,然后自己的励志奖也定下来一定得了,在火车上的我们也松了一口气,不能因为来比赛国奖励志奖都不得是不--

弱渣的牡丹江现场赛之旅流水账

下午就要坐卧铺赶回北京了,闲来无事,写个总结,给以后的自己看. 由于孔神要保研面试,所以只有我们队里三个人上路.我们是周五坐的十二点出发的卧铺,一路上不算无聊,恰巧邻床是北航的神犇,于是下午和北航神犇玩了一段时间的杀人游戏,晚上还旁观昂神与众神谈论职场形式,未来出路,觉得听着有豁然开朗的感觉(听说网上卖菜比搞IT赚的更多,也是醉了),无限YM中...不过虽然是卧铺,想入睡也不是那么容易,睡睡醒醒,也挺折腾 第二天七点多到的牡丹江,感觉虽然都是东北,不过这个小城显然不如我家沈阳繁华,尤其是大早上,