【学习笔记】CF1835D Doctor‘s Brown Hypothesis

有点难

发现 x , y x,y x,y在一个强连通块内,这样一定有环

发现可以找到强连通块内所有环长度的 gcd ⁡ \gcd gcd,这样从 x x x y y y的所有路径的长度都模这个数同余,又因为 K K K非常大,所以我们总可以遍历整个强连通块并走若干个环,因此只需要从 x x x y y y的任意一条路径的长度和 K K K gcd ⁡ \gcd gcd同余即可

首先要做过这道题 [ABC306G] Return to 1

发现直接 D F S DFS DFS即可,感觉没啥区别啊

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include
#define fi first
#define se second
#define pb push_back
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m;
int dfn[N],low[N],num,vs[N],cnt;
int dis[N],ps[N],sz[N],g;
ll K,res;
vector<int>G[N];
stack<int>s;
int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}
vector<int>vec;
void dfs(int u){
    vec.pb(dis[u]);
    for(auto v:G[u]){
        if(ps[v]!=cnt)continue;
        if(dis[v]==-1)dis[v]=dis[u]+1,dfs(v);
        else g=gcd(g,abs(dis[u]+1-dis[v]));
    }
}
ll calc(ll x){
    return x*(x+1)/2;
}
void tarjan(int u){
    dfn[u]=low[u]=++num,vs[u]=1,s.push(u);
    for(auto v:G[u]){
        if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
        else if(vs[v])low[u]=min(low[u],dfn[v]);
    }if(low[u]==dfn[u]){
        int tmp;cnt++;
        do{
            tmp=s.top(),s.pop();
            vs[tmp]=0,ps[tmp]=cnt,ps[tmp]=cnt;
        }while(tmp!=u);
        g=0,dis[u]=0,vec.clear(),dfs(u);
        if(g){
            for(auto e:vec)sz[e%g]++;
            if(K%g==0){
                for(int i=0;i<g;i++){
                    res+=calc(sz[i]);
                }
            }
            if(g%2==0&&K%g==g/2){
                for(int i=0;i<g;i++){
                    int j=(i+g/2)%g;
                    if(i<j)res+=(ll)sz[i]*sz[j];
                }
            }
            for(auto e:vec)sz[e%g]--;
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m>>K,memset(dis,-1,sizeof dis);
    for(int i=1;i<=m;i++){
        int x,y;cin>>x>>y;
        G[x].pb(y);
    }for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    cout<<res;
}

你可能感兴趣的:(学习,笔记,图论)