NOIP2020 排水系统
几度欲写,却望高精而却步,今习得__int128,君子报仇,一年不晚。
NOIP2020 排水系统
DAG图,拓扑就好,核心难点在于毒瘤的分数的操作,毕竟只是T!只有分数相加,就很简单了。
a/b + x/y = (ay+bx)/by
约分
a/=gcd(a,b) b/gcd(a,b)
本来到这里就结束了的(当时我就是这么想的)然鹅ccf还藏有后手:
不会经过超过10个中间排水结点,你以为这是告诉你数据不大对吧,由于每次最多分成1/5可以最多分5次,途中还可能有汇入的,每次分母都相乘。假如只有两个接水点,一个排水点,分母都可以达到5^20,longlong都存不下。
几次刷到这题,看到高精我就走了,直到我学到了__int128。
所以,15分钟一遍就A了。
代码:
#include<bits/stdc++.h> #define INT __int128 using namespace std; const int MM=500005; stack<int> s; int u,n,m,chu[MM],ru[MM],tot,nxt[MM],head[MM],to[MM],now; long long fz[MM],fm[MM],G; inline void output(__int128 x) { if(x>9) output(x/10); putchar(x%10+'0'); } void add(int u,int v) { nxt[++tot]=head[u]; head[u]=tot; to[tot]=v; } INT gcd(INT a,INT b) { if(!b) return a; return gcd(b,a%b); } void topsort() { while(!s.empty()) { now=s.top(); s.pop(); if(fz[now]==0||chu[now]==0)continue; fm[now]*=chu[now]; G=gcd(fz[now],fm[now]); fz[now]/=G; fm[now]/=G; for(int i=head[now];i;i=nxt[i]) { int v=to[i]; fz[v]*=fm[now]; fz[v]+=fz[now]*fm[v]; fm[v]*=fm[now]; G=gcd(fz[v],fm[v]); fz[v]/=G; fm[v]/=G; ru[v]--; if(!ru[v]) s.push(v); } } } int main() { cin>>n>>m; for(int i=1;i<=n;i++) { fm[i]=1; if(i<=m) fz[i]=1; cin>>chu[i]; for(int j=1;j<=chu[i];j++) { cin>>u; ru[u]++; add(i,u); } } for(int i=1;i<=n;i++) if(!ru[i]) s.push(i); topsort(); for(int i=1;i<=n;i++) if(!chu[i]) output(fz[i]),cout<<' ',output(fm[i]),cout<<endl; return 0; }