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;
} 

 

posted @ 2021-09-11 13:54  T_X蒻  阅读(127)  评论(0编辑  收藏  举报