水坝排水系统c语言,题解 NOIP2020 T1 排水系统

带 gcd 的纯模拟。( gcd 就是求最大公约数)

gcd 用来处理分数相加时的分母通分和分数的约分,

通过 gcd 珂以求出 lcm (最小公倍数):

\\(\\operatorname{lcm}(x,y)=\\frac{x \\times y}{\\gcd(x,y)}\\)

开个结构体存分数,然后就珂以愉快地拓扑排序了。

最后几个点 WA 是因为 long long 不够用,

开个 __int128 就能过了。

考场上就乖乖写高精吧(逃

代码:

#include

#include

#include

#include

#include

#include

#include

#define Rei register int

#define ll __int128//注意是两个下划线!

using namespace std;

template

inline void read(T &x) {

x=0;

char f=0,c;

while(c=getchar(),!isdigit(c)) if(c==\'-\') f=1;

if(f) while(isdigit(c)) x=x*10-c+48,c=getchar();

else while(isdigit(c)) x=x*10+c-48,c=getchar();

}

void write(__int128 x) {//__int128需要手写输入输出

if(x/10) write(x/10);

putchar(x%10+\'0\');

}

inline ll gcd(ll x,ll y) {//辗转相除法求gcd

ll t;

while(y) t=x%y,x=y,y=t;

return x;

}

const int N=1e5+2;

int n,m,cnt,rbq,son;

int h[N],rd[N],d[N];

struct node {

int next,to;

node(int next=0,int to=0) {

this->next=next,this->to=to;

}

} b[N*5];

struct fenshu {

ll fenzi,fenmu;

fenshu(ll fenzi=0,ll fenmu=1) {//注意分母不能为0

this->fenzi=fenzi,this->fenmu=fenmu;

}

void huajian() {//分数的化简

ll g=gcd(fenzi,fenmu);

fenzi/=g,fenmu/=g;

}

} O2[N];

fenshu jia(fenshu x,fenshu y) {//这里自己推一下就懂了

ll g=gcd(x.fenmu,y.fenmu);

ll k1=y.fenmu/g,k2=x.fenmu/g;

return fenshu(x.fenzi*k1+y.fenzi*k2,x.fenmu*k1);

}

inline void link(int u,int v) {

b[++cnt]=node(h[u],v),h[u]=cnt,++rd[v];

}

queue q;

vector ans;

void tuopu() {//拓扑排序

for(Rei i=1; i<=n; ++i) {

if(!rd[i]) {

q.push(i);

O2[i]=fenshu(1,1);

}

}

while(!q.empty()) {

rbq=q.front(),q.pop();

if(!d[rbq]) {

ans.push_back(rbq);

continue;

}

O2[rbq].fenmu*=d[rbq];//水分流

O2[rbq].huajian();

for(Rei i=h[rbq]; i; i=b[i].next) {

--rd[son=b[i].to];

O2[son]=jia(O2[son],O2[rbq]);

O2[son].huajian();

if(!rd[son]) {

q.push(son);

}

}

}

}

int main() {

read(n),read(m);

for(Rei i=1; i<=n; ++i) {

read(d[i]);

for(Rei j=1; j<=d[i]; ++j) {

read(rbq),link(i,rbq);

}

}

tuopu();

sort(ans.begin(),ans.end());

for(int i=0; i

write(O2[ans[i]].fenzi),putchar(\' \');

write(O2[ans[i]].fenmu),putchar(\'\\n\');

}

return 0;

}

第一次写题解,请多包涵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值