Regional 2014 - Asia Mudanjiang - F Fiber-optic Network

来源:互联网 发布:价值投资数据类app 编辑:程序博客网 时间:2024/05/29 18:38

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=647&page=show_problem&problem=4986

题意:
有一棵N个节点的树,点有点权,第i个节点的权值属于[Li,Ri],并且要求相邻节点的点权是互质的。对于每个节点,计算这个节点在所有合法方案中的点权之和。输出的值对109+7取模。
1N50,1LiRi50000

题解:

将问题转化为计算每个节点i取值j的方案数,可以发现是经典的两遍树DP问题,第一遍算子树满足条件时根取值的方案,第二遍算全树满足条件时某个点取值的方案。

首先进行第一遍树DP,令f[i][j]表示以i为根的子树满足条件且i取值j的方案数,M=max1iNRi,则有

f[u][i]=v is the son of ugcd(i,j)=1f[v][j]=v is the son of ujf[v][j]d|id|jμ(d)=v is the son of ud|iμ(d)d|jf[v][j]=v is the son of ud|iμ(d)g[v][d]=v is the son of uh[v][i]
,其中g[v]相当于是f[v]的狄利克雷卷积,h[v]则相当于是vu产生的贡献,这样做是O(NMlogM)的。

注意到这里h[v][i]在模意义下可能是0,为了避免第二遍树DP涉及除法,需要给u的孩子进行顺序标号,并定义pre[v][i]=v is the son of u,posv<posvh[v][i]suf[v][i]=v is the son of u,posv>posvh[v][i],这样就有pre[v]suf[v]表示不考虑v这棵子树时v父亲的子树合法的方案数。

第二遍树DP主要是将v父亲u的贡献向v产生,不妨用h[v]表示其父亲对其产生的贡献,则实际为把h[u]pre[v]suf[v]当作f[u]而产生的贡献,类似地计算即可,还是O(NMlogM)的。

注意下边界条件然后就没了。

代码:

#include <vector>#include <stdio.h>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const int maxn = 51, maxm = 50001, mod = 1000000007;int t, n, mx, l[maxn], r[maxn], mu[maxm];int f[maxn][maxm], g[maxn][maxm], h[maxn][maxm];int pre[maxn][maxm], suf[maxn][maxm];vector<int> e[maxn];inline void mod_inc(int &x, int y){    if((x += y) >= mod)        x -= mod;}inline void mod_dec(int &x, int y){    if((x -= y) < 0)        x += mod;}void pfs(int u){    int sz = e[u].size();    for(int i = 0; i < sz; ++i)    {        int v = e[u][i];        e[v].erase(remove(e[v].begin(), e[v].end(), u), e[v].end());        pfs(v);    }    memset(f[u] + 1, 0, mx * sizeof(int));    if(sz > 0)    {        { // pre            int p, v = e[u][0];            for(int i = l[u]; i <= r[u]; ++i)                pre[v][i] = 1;            for(int i = 1; i < sz; ++i)            {                p = v, v = e[u][i];                for(int j = l[u]; j <= r[u]; ++j)                    pre[v][j] = (LL)pre[p][j] * h[p][j] % mod;            }        }        { // suf            int p, v = e[u][sz - 1];            for(int i = l[u]; i <= r[u]; ++i)                suf[v][i] = 1;            for(int i = sz - 2; i >= 0; --i)            {                p = v, v = e[u][i];                for(int j = l[u]; j <= r[u]; ++j)                    suf[v][j] = (LL)suf[p][j] * h[p][j] % mod;            }        }        for(int i = l[u]; i <= r[u]; ++i)            f[u][i] = (LL)suf[e[u][0]][i] * h[e[u][0]][i] % mod;    }    else        for(int i = l[u]; i <= r[u]; ++i)            f[u][i] = 1;    memcpy(g[u] + 1, f[u] + 1, mx * sizeof(int));    for(int i = 1; i <= mx; ++i)        for(int j = i + i; j <= mx; j += i)            mod_inc(g[u][i], g[u][j]);    memset(h[u] + 1, 0, mx * sizeof(int));    for(int i = 1; i <= mx; ++i)        if(mu[i] > 0)            for(int j = i; j <= mx; j += i)                mod_inc(h[u][j], g[u][i]);        else if(mu[i] < 0)            for(int j = i; j <= mx; j += i)                mod_dec(h[u][j], g[u][i]);}void dfs(int u){    for(int i = l[u]; i <= r[u]; ++i)        f[u][i] = (LL)f[u][i] * h[u][i] % mod;    for(vector<int>::iterator it = e[u].begin(); it != e[u].end(); ++it)    {        int v = *it;        memset(g[u] + 1, 0, mx * sizeof(int));        for(int i = l[u]; i <= r[u]; ++i)            g[u][i] = (LL)pre[v][i] * suf[v][i] % mod * h[u][i] % mod;        for(int i = 1; i <= mx; ++i)            for(int j = i + i; j <= mx; j += i)                mod_inc(g[u][i], g[u][j]);        memset(h[v] + 1, 0, mx * sizeof(int));        for(int i = 1; i <= mx; ++i)            if(mu[i] > 0)                for(int j = i; j <= mx; j += i)                    mod_inc(h[v][j], g[u][i]);            else if(mu[i] < 0)                for(int j = i; j <= mx; j += i)                    mod_dec(h[v][j], g[u][i]);        dfs(v);    }}int main(){    mu[1] = 1;    for(int i = 1; i < maxm; ++i)        for(int j = i + i; j < maxm; j += i)            mu[j] -= mu[i];    scanf("%d", &t);    while(t--)    {        scanf("%d", &n);        for(int i = 1; i <= n; ++i)            scanf("%d", l + i);        mx = 0;        for(int i = 1; i <= n; ++i)        {            scanf("%d", r + i);            if(mx < r[i])                mx = r[i];        }        for(int i = 1; i <= n; ++i)            vector<int>().swap(e[i]);        for(int i = 1, u, v; i < n; ++i)        {            scanf("%d%d", &u, &v);            e[u].push_back(v);            e[v].push_back(u);        }        pfs(1);        for(int i = l[1]; i <= r[1]; ++i)            h[1][i] = 1;        dfs(1);        for(int i = 1; i <= n; ++i)        {            int ans = 0;            for(int j = l[i]; j <= r[i]; ++j)                ans = (ans + (LL)j * f[i][j]) % mod;            printf("%d%c", ans, " \n"[i == n]);        }    }    return 0;}
0 0