51nod 1610 路径计数(容斥+dp)

路径计数
System Message (命题人)
基准时间限制:1 秒 空间限制:131072 KB 分值: 80
路径上所有边权的最大公约数定义为一条路径的值。
给定一个有向无环图。
T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对1,000,000,007取模)。
Input
第一行两个整数n和m,分别表示有向无环图上的点数和边数。(1<=n<=100,1<=m<=50,000)
第2~m+1行每行三个数x,y,z,表示有一条从x到y权值为z的边。(1<=x,y<=n,1<=z<=100)
第m+2行一个数T,表示修改操作次数(1<=T<=500)。
接下来T行每行两个数x,y,表示修改第x条边(按照读入的顺序)的边权为y(1<=x<=m,1<=y<=100)。
Output
T+1行,修改前和每次修改操作后输出答案。
Input示例
4 4
1 2 2
2 4 3
1 3 4
3 4 2
4
1 5
2 10
3 3
4 6
Output示例
1
1
0
1
0


gcd=1gcd1100100
gcdO(100n2)
500GG
gcd3gcd=2
mat[k][i][j]kij
i
i

O(Tvn2)O(Tsqrt(v)n2)


代码:

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          1000005
#define   maxnode       205
#define   sigma_size    2
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
//const double pi    = acos(-1.0);
const double inf   = 1e18;
//const double eps   = 1e-9;
const LL     mod   = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/

LL dp[105];
int a[50005],b[50005],c[50005];
int mat[105][105][105];
LL g[105];
LL f[105];
int n;

LL dfs(int u,int d){
    if(dp[u]!=-1) return dp[u];
    LL ans=0;
    for(int i=1;i<=n;i++){
        if(mat[d][u][i]){
            ans=(ans+mat[d][u][i]+mat[d][u][i]*dfs(i,d))%mod;
        }
    }
    return dp[u]=ans;
}
LL cal(int u){
    mem(dp,-1);
    for(int i=1;i<=n;i++){
        if(dp[i]==-1) dfs(i,u);
    }
    LL ans=0;
    for(int i=1;i<=n;i++) ans=(ans+dp[i])%mod;
    return ans;
}
int main(){
    //freopen("in.txt","r",stdin);
    int m;
    cin>>n>>m;
    mem(mat,0);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
        for(int j=1;j*j<=c[i];j++){
            if(c[i]%j==0){
                mat[j][a[i]][b[i]]++;
                if(c[i]/j!=j) mat[c[i]/j][a[i]][b[i]]++;
            }
        }
    }
    for(int i=1;i<=100;i++) g[i]=cal(i);
    for(int i=100;i>0;i--){
        f[i]=g[i];
        for(int j=2*i;j<=100;j+=i){
            f[i]-=f[j];
        }
        f[i]=(f[i]%mod+mod)%mod;
    }
    cout<<f[1]<<endl;
    int t;
    cin>>t;
    while(t--){
        int x,y;
        scanf("%d%d",&x,&y);
        vector<int> v;
        for(int i=1;i*i<=c[x];i++){
            if(c[x]%i==0){
                mat[i][a[x]][b[x]]--;
                v.push_back(i);
                if(c[x]/i!=i) mat[c[x]/i][a[x]][b[x]]--,v.push_back(c[x]/i);
            }
        }
        c[x]=y;
        for(int i=1;i*i<=c[x];i++){
            if(c[x]%i==0){
                mat[i][a[x]][b[x]]++;
                v.push_back(i);
                if(c[x]/i!=i) mat[c[x]/i][a[x]][b[x]]++,v.push_back(c[x]/i);
            }
        }
        for(int i=0;i<v.size();i++){
            g[v[i]]=cal(v[i]);
        }
        for(int i=100;i>0;i--){
            f[i]=g[i];
            for(int j=2*i;j<=100;j+=i){
                f[i]-=f[j];
            }
            f[i]=(f[i]%mod+mod)%mod;
        }
        cout<<f[1]<<endl;
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值