其他分享
首页 > 其他分享> > NOIP2020

NOIP2020

作者:互联网

P7113 NOIP2020排水系统

题目描述
对于一个城市来说,排水系统是极其重要的一个部分。
有一天,小 C 拿到了某座城市排水系统的设计图。排水系统由 n 个排水结点(它们从1∼n 编号)和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水结点的污水(简称为该结点的汇集管道),也有若干个管道向其他的排水结点排出污水(简称为该结点的排出管道)。
排水系统的结点中有 m个污水接收口,它们的编号分别为 1,2,3, m污水只能从这些接收口流入排水系统,并且这些结点没有汇集管道。排水系统中还有若干个最终排水口,它们将污水运送到污水处理厂,没有排出管道的结点便可视为一个最终排水口。
现在各个污水接收口分别都接收了1 吨污水,污水进入每个结点后,会均等地从当前结点的每一个排出管道流向其他排水结点,而最终排水口将把污水排出系统。
现在小 C 想知道,在该城市的排水系统中,每个最终排水口会排出多少污水。该城市的排水系统设计科学,管道不会形成回路,即不会发生污水形成环流的情况。
输入格式
第一个两个用单个空格分隔的整数 n,m。分别表示排水结点数与接收口数量。
接下来 n行,第 i 行用于描述结点 i 的所有排出管道。其中每行第一个整数
表示其排出管道的数量,接下来个用单个空格分隔的整数依次表示管道的目标排水结点。
保证不会出现两条起始结点与目标结点均相同的管道。
输出格式
输出若干行,按照编号从小到大的顺序,给出每个最终排水口排出的污水体积。其中体积使用分数形式进行输出,即每行输出两个用单个空格分隔的整数 p,q,表示排出的污水体积为p / q。要求 p 与 q 互素,q = 1 时也需要输出 q。
输入 #1

5 1
3 2 3 5
2 4 5
2 5 4
0
0

输出 #1

1 3
2 3

输入 #2

10 1
5 2 3 4 5 6
2 7 8
2 8 10
2 9 7
1 9
3 7 8 9
1 10
0
1 10
0

输出 #2

4 15
11 15

分析
保证不会出现两条起始结点与目标结点均相同的管道。这表明了这是一个裸的拓扑排序,需要注意的是用分数表示,分数要约分到最简,还有这毒瘤的数据。
unsigned long long 也过不了,会WA一个点,需要用__int128.
注意printf和cout 都无法输出__int 128的数据,需要用字符形式输出。
代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cstring>
#define  lll  __int128
using namespace std;
const int N=2e7;
lll gcd(lll a,lll b)
{
    if(b == 0)  return a;
    return gcd(b,a%b);
}
struct  edge{
    int from;
    int to;
    int dis;
    int next;
}e[N];
int head[N],cnt;
void add(int u,int v)
{
    ++cnt;
    e[cnt].from = u;
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
struct node{
    lll son;
    lll mom;
    node()
    {
        lll son = 0;
        lll mom = 0;
    }
}ans[N];
node check(node a,node b)
{
    node sum;
    if(a.son == 0 && a.mom == 0)
    {
        sum.son = b.son;
        sum.mom = b.mom;
        return sum;
    }
    lll p = a.mom/gcd(a.mom,b.mom)*b.mom;
    sum.mom = p;
    sum.son = (p/a.mom*a.son)+(p/b.mom*b.son);
    lll t = gcd(sum.son,sum.mom);
    sum.son /= t;
    sum.mom /= t;
    return sum;
}
int n,m;
int x;
int num[N];
int ru[N],chu[N];
queue<int> q;
void print(lll n) {
    if(n > 9) print(n / 10);
    putchar(n % 10 + 48);
    //n % 10+'0'(48)表示字符0~9   
    //putchar输出的是字符。
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>num[i];
        for(int j=1;j<=num[i];j++)
        {
            cin>>x;
            add(i,x);
            ru[x]++;
            chu[i]++; 
        }
    }
    for(int i=1;i<=n;i++)
    if(ru[i] == 0)
    {
        q.push(i);
        ans[i].son = 1;
        ans[i].mom = 1;
    }
    while(!q.empty())
    {
        int x = q.front();
        if(num[x] != 0) ans[x].mom *= num[x];
        q.pop();
        for(int i=head[x];i;i=e[i].next)
        {
            int y = e[i].to;
            ans[y] = check(ans[y],ans[x]);
            ru[y]--;
            if(ru[y] == 0) q.push(y);
            //cout<<y<<" "<<ans[y].son<<" "<<ans[y].mom<<endl;
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(chu[i] == 0)
        {
            lll w = gcd(ans[i].son,ans[i].mom);
            ans[i].mom /= w;//再约分一次保证互质
            ans[i].son /= w;
            print(ans[i].son);
            printf(" ");
            print(ans[i].mom);
            printf("\n");
        }
        
    }
    return 0;
}

标签:结点,int,sum,污水,mom,lll,NOIP2020
来源: https://www.cnblogs.com/Elgina/p/15362511.html