51Nod 算法马拉松17 路径计数 莫比乌斯函数加暴力构图

来源:互联网 发布:宾得k3 知乎 编辑:程序博客网 时间:2024/04/30 06:12

题目大意

现在定义路径上所有边权的最大公约数定义为一条路径的值。
现在给定一个N个点M条边有向无环图。进行T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对109取模)。

N100
M50000
T500
100

解题思路

我们可以用莫比乌斯来做这题,设Fi为边权为i的倍数的路径的数量,最后答案就是100i=1Fimiui。那么考虑现在怎么得到F数组。

我们知道一个数的约数最多就只有根号个,而且这题的边权最大只有100,那么考虑建100幅图,在第i幅图统计Fi的答案。而对于一条边权为Aj连接u,v的边,假如Aj % k=0那么就在第k幅图的u,v连一条边。对于Fi就是第i幅图的路径条数。而修改只有500次,复杂度是OTmaxAiN。足以通过本题。

程序

//YxuanwKeith#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int MAXN = 105, MAXM = 5e4 + 5;const int Mo = 1e9 + 7;struct Node {    int u, v, w;} Q[MAXM];bool Flag[MAXN];int N, M, Mu[MAXN], Fac[MAXN];int tot[MAXN], Ans[MAXN];struct Solve {    int Map[MAXN][MAXN], Num[MAXN], Ord[MAXN], F[MAXN], Ans;    void Get() {        for (int i = 1; i <= N; i ++)            for (int j = 1; j <= N; j ++)                 Num[j] += Map[i][j];        static int D[MAXN];        int top = 0, p = 0;        for (int i = 1; i <= N; i ++)            if (!Num[i]) D[++ top] = i;        while (top) {            int Now = D[top --];            Ord[++ p] = Now;            for (int i = 1; i <= N; i ++)                 if (Map[Now][i]) {                    Num[i] -= Map[Now][i];                    if (!Num[i]) D[++ top] = i;                }         }        Ans = 0;        for (; p; p --) {            int Now = Ord[p];            F[Now] = 1;            for (int i = 1; i <= N; i ++)                 F[Now] = (F[Now] + Map[Now][i] * 1ll * F[i] % Mo) % Mo;            Ans = (Ans + F[Now] - 1) % Mo;        }    }} P[MAXN];int Prep() {    Mu[1] = 1;    for (int i = 2; i < MAXN; i ++) {        if (!Flag[i]) {            Mu[i] = -1;            Fac[++ Fac[0]] = i;        }        for (int j = 1; j <= Fac[0]; j ++) {            if (1ll * i * Fac[j] >= MAXN) break;            Flag[i * Fac[j]] = 1;            if (i % Fac[j]) Mu[i * Fac[j]] = -Mu[i]; else {                Mu[i * Fac[j]] = 0;                break;            }        }    }}int main() {    scanf("%d%d", &N, &M);    Prep();    for (int i = 1; i <= M; i ++)         scanf("%d%d%d", &Q[i].u, &Q[i].v, &Q[i].w);    for (int i = 1; i <= M; i ++)         for (int j = 1; j <= Q[i].w; j ++)             if (Q[i].w % j == 0 && Mu[j] != 0) P[j].Map[Q[i].u][Q[i].v] ++;    int Ans = 0;    for (int i = 1; i < MAXN; i ++)         if (Mu[i] != 0) {            P[i].Get();            Ans = ((Ans + P[i].Ans * 1ll * Mu[i]) % Mo + Mo) % Mo;        }    printf("%d\n", Ans);    int C;    scanf("%d\n", &C);    for (int i = 1; i <= C; i ++) {        int Ord, Val;        scanf("%d%d", &Ord, &Val);        memset(Flag, 0, sizeof Flag);        for (int j = 1; j <= Q[Ord].w; j ++)             if (Q[Ord].w % j == 0 && Mu[j]) {                P[j].Map[Q[Ord].u][Q[Ord].v] --;                Flag[j] = 1;            }        Q[Ord].w = Val;        for (int j = 1; j <= Q[Ord].w; j ++)             if (Q[Ord].w % j == 0 && Mu[j]) {                P[j].Map[Q[Ord].u][Q[Ord].v] ++;                Flag[j] = 1;            }        for (int j = 1; j < MAXN; j ++)             if (Mu[j] && Flag[j]) P[j].Get();        Ans = 0;        for (int j= 1; j < MAXN; j ++)             if (Mu[j]) Ans = ((Ans + P[j].Ans * Mu[j]) % Mo + Mo) % Mo;         printf("%d\n", Ans);    }}
2 0
原创粉丝点击