51nod 1610 路径计数

原题连接:
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1610

  f(n) 为路径值为 n 的路径数量。

记,F(n)为路径值为 n 的倍数的路径数量,即:
F(n)=n|df(d)

ans=f(1)=d1μ(d)F(d)

考虑不同权重为 d 的倍数的边组成的图.

F(d)为此图中。路径总数量。

由于 m50000 .明显会出现重边。
建议限制边的数量或者使用邻接矩阵存图。
矩阵更为方便。
由于最初没有考边过多。使用了链表+拓扑排序。代码量较大。
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <vector>
#define MAXM 50210
#define MAXN 105
using namespace std;
typedef long long LL;
const int P=1e9+7;
const int P_=P-1;

struct Io
{
    const char l='0'-1;
    const char r='9'+1;
    char A[MAXM*10];
    char *ptop,*pend;
    Io()
    {
        ptop=pend=A;
    }
    void Io_fread()
    {
        pend=A+fread(A,1,MAXN,stdin);
        ptop=A;
    }
    bool read(int &a)//返回false表示什么也没读到
    {
        if(ptop==pend)Io_fread();
        if(ptop==pend)return false;
        while(*ptop==' '||*ptop=='\n'||*ptop=='\r'||*ptop=='\t')
        {
            ptop++;
            if(ptop==pend)
            {
                Io_fread();
                if(ptop==pend)return false;
            }
        }
        a=0;
        while(*ptop>l&&*ptop<r&&ptop<pend)
        {
            a=a*10+(*(ptop++)-'0');
            if(ptop==pend) Io_fread();
        }
        return true;
    }
}I;
struct node
{
    int to,next;
    node(int to,int next):to(to),next(next){}
    node()
    {
        *this=node(0,0);
    }
}G[MAXM];//返图。方便topsort

struct edge
{
    int from,to,w,L,R,cnt;
    edge(int from,int to,int w):from(from),to(to),w(w){};
    edge(int to,int w,int L,int R):to(to),w(w),L(L),R(R){}
    edge()
    {
        *this=edge(0,0,0,0);
        cnt=0;
        from=0;
    }

}E[MAXN][20000];

vector<int>V[MAXN];
int Ginof[MAXN];
int inof[MAXN][MAXN];
int mu[MAXN]={0,-1},out[MAXN],ans[MAXN],dp[MAXN];
int F[MAXM][3],F2[MAXM][3];
int name[MAXN][MAXN];
void add(edge &e,int deep)
{
    out[e.from]++;
    G[deep]=node(e.from,Ginof[e.to]);
    Ginof[e.to]=deep;
}

void build(int t,int deep)//将deep调边录入t集合内
{
    E[t][deep].cnt++;
    if(E[t][deep].cnt>1)return;
    edge &e=E[t][deep];
    if(!e.from)
    {
        e.from=F2[deep][0];
        e.to=F2[deep][1];
    }
    int &d=inof[t][e.from];
    e.L=E[t][d].L;
    e.R=d;
    E[t][E[t][d].L].R=deep;
    E[t][d].L=deep;
}

void Remove(int t,int deep)//删除
{
    E[t][deep].cnt--;
    if(E[t][deep].cnt)return;
    E[t][E[t][deep].L].R=E[t][deep].R;
    E[t][E[t][deep].R].L=E[t][deep].L;
    E[t][deep].R=E[t][deep].L=0;
}

int Q[MAXN],A[MAXN];
void topsort(int n);
int slove(int d,int n);//d倍数权重的图上计算边数;
int clat();

int main ()
{
    for(int i=1;i<MAXN;i++)
    {
        mu[i]=-mu[i];
        for(int j=i<<1;j<MAXN;j+=i)mu[j]+=mu[i];
    }//计算 莫比乌斯函数。
    for(int i=1;i<MAXN;i++)
        for(int j=i;j<MAXN;j+=i)
            V[j].push_back(i);

    for(int i=1;i<101;i++)
        for(int j=1;j<101;j++)
            inof[i][j]=j+50002;

    int n,m,x,y,T;

    I.read(n);
    I.read(m);
    int deep=1;
    for(int i=1;i<=m;i++)
    {
        I.read(F[i][0]);
        I.read(F[i][1]);
        I.read(F[i][2]);
        if(name[F[i][0]][F[i][1]]==0)
        {
            F2[deep][0]=F[i][0];
            F2[deep][1]=F[i][1];
            name[F[i][0]][F[i][1]]=deep++;
        }
        int &d=F[i][2],&b=name[F[i][0]][F[i][1]];
        for(int j=0;j<(int)V[d].size();j++)
        {
            int u=V[d][j];
            build(u,b);
        }
        add(E[d][b],i);
    }

    topsort(n);
    for(int i=1;i<101;i++)ans[i]=slove(i,n);
    int ANS=clat();
    printf("%d\n",ANS);
    I.read(T);
    while(T--)
    {
        I.read(x);
        I.read(y);
        int w=F[x][2];
        F[x][2]=y;
        x=name[F[x][0]][F[x][1]];
        for(int i=0;i<V[w].size();i++)
        {
            int d=V[w][i];
            Remove(d,x);
        }
        for(int i=0;i<V[y].size();i++)
        {
            int d=V[y][i];
            build(d,x);
        }
        for(int j=1;j<V[y].size();j++)
        {
            int &i=V[y][j];
            ANS-=mu[i]*ans[i];
            if(ANS<0)ANS+=P;
            if(ANS>P_)ANS-=P;
            ans[i]=slove(i,n);
            ANS+=mu[i]*ans[i];
            if(ANS<0)ANS+=P;
            if(ANS>P_)ANS-=P;
        }
        for(int j=1;j<V[w].size();j++)
        {
            int &i=V[w][j];
            if(y%i)
            {
                ANS-=mu[i]*ans[i];
                if(ANS<0)ANS+=P;
                if(ANS>P_)ANS-=P;
                ans[i]=slove(i,n);
                ANS+=mu[i]*ans[i];
                if(ANS<0)ANS+=P;
                if(ANS>P_)ANS-=P;
            }
        }
        printf("%d\n",ANS);
    }
    return 0;
}

void topsort(int n)
{
    int l=0,r=0;
    for(int i=1;i<=n;i++)
    {
        if(out[i])continue;
        Q[r++]=i;
    }
    while(l<r)
    {
        int v=Q[l++];
        A[n--]=v;
        for(int i=Ginof[v];i;i=G[i].next)
        {
            node &e=G[i];
            out[e.to]--;
            if(out[e.to])continue;
            Q[r++]=e.to;
        }
    }
}

int slove(int d,int n)
{
    int tmp=0;
    memset(dp,0,sizeof dp);
    for(int i=n;i;i--)
    {
        int v=A[i];
        for(int j=E[d][inof[d][v]].L;j;j=E[d][j].L)
        {
            edge &e=E[d][j];
            dp[v]+=((LL)e.cnt*dp[e.to]+e.cnt)%P;
            if(dp[v]>P_)dp[v]-=P;
        }
        tmp+=dp[v];
        if(tmp>P_)tmp-=P;
    }
    return tmp;
}

int clat()
{
    int tmp=0;
    for(int i=1;i<101;i++)
    {
        tmp=(tmp+ans[i]*mu[i]);
        if(tmp>P_)tmp-=P;
        if(tmp<0)tmp+=P;
    }
    return tmp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值