LGP7113 [NOIP 2020] 排水系统 学习笔记

LGP7113 [NOIP 2020] 排水系统 学习笔记

Luogu Link

题意简述

给定一个 \(n\) 个点的 \(\texttt{DAG}\)。我们认为它是一个排水系统。

节点 \(u\)\(d_u\) 条输出管道,污水会被平分成 \(d_u\) 份流向下家节点。特别的,\(d_u=0\) 时认为这个节点直通污水厂,是一个最终排水口。

对于其中 \(1\sim m\) 这些点,它们会接收到 \(1\) 吨污水。保证他们不被任何节点指向。问每个最终排水口会排出多少污水。答案请用最简分数表示。

\(0\le d_u\le 5\)\(n\le 10^5\)\(m\le 10\)。保证没有任何一滴水会经过 \(10\) 个以上的中间节点(接收节点和最终排水口不算在内)。

做法解析

拓扑排序即可。

但是这题的数据范围?分母理论上来说可以干到 \(2^{11}\times 3^{11}\times 5^{11}\) 附近。因为水量的绝对数值最多是 \(m=10\),所以分子理论最高就是 \(30\times 10^{11}\times 10=3\times 10^13\)。按理来说这些还在 long long 范围内啊。但是一般而言,通分的过程是 \(\frac{a}{c}+\frac{b}{d}=\frac{ad+bc}{cd}\)。这一步就爆 long long 了。最简单的解决方法是直接用 __int128,毕竟 long long 范围的两倍就是 __int128 范围。另外实际上由于分母只有若干 \(2,3,5\) 组成,所以你不妨去维护一下分子和分母 \(2,3,5\) 的含量。不过有现成的 __int128 为什么不用呢?

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5;
int N,M,X;
vector<int> Gr[MaxN];
int ind[MaxN],oud[MaxN];
void addedge(int u,int v){Gr[u].push_back(v),ind[v]++;}
molo fz[MaxN],fm[MaxN];queue<int> q;
molo agcd(molo x,molo y){return y?agcd(y,x%y):x;}
void solve(){
    for(int i=1;i<=N;i++)fm[i]=1;
    for(int i=1;i<=M;i++)fz[i]=1,q.push(i);
    while(q.size()){
        int u=q.front();q.pop();
        if(!oud[u])continue;
        fm[u]*=oud[u];
        for(int v : Gr[u]){
            ind[v]--;
            fz[v]=fz[u]*fm[v]+fz[v]*fm[u],fm[v]*=fm[u];
            molo cg=agcd(fz[v],fm[v]);fz[v]/=cg,fm[v]/=cg;
            if(!ind[v])q.push(v);
        }
    }
}
int main(){
    readis(N,M);
    for(int i=1;i<=N;i++){
        readi(oud[i]);
        for(int j=1;j<=oud[i];j++)readi(X),addedge(i,X);
    }
    solve();
    for(int i=1;i<=N;i++)if(!oud[i])writip(fz[i]),writil(fm[i]);
    return 0;
}

反思总结

__int128 还是太伟大了。除了在你对它直接套 abs() 的时候。

posted @ 2025-09-12 16:10  矞龙OrinLoong  阅读(14)  评论(0)    收藏  举报