NOIP2020 题解&感悟

1 排水系统

problem

对于一个城市来说,排水系统是极其重要的一个部分。

有一天,小 C 拿到了某座城市排水系统的设计图。排水系统由 \(n\) 个排水结点(它们从 \(1 \sim n\)编号)和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水结点的污水(简称为该结点的汇集管道),也有若干个管道向其他的排水结点排出污水(简称为该结点的排出管道)。

排水系统的结点中有 \(m\) 个污水接收口,它们的编号分别为 \(1, 2, \ldots , m\)污水只能从这些接收口流入排水系统,并且这些结点没有汇集管道。排水系统中还有若干个最终排水口,它们将污水运送到污水处理厂,没有排出管道的结点便可视为一个最终排水口。

现在各个污水接收口分别都接收了 \(1\) 吨污水,污水进入每个结点后,会均等地从当前结点的每一个排出管道流向其他排水结点,而最终排水口将把污水排出系统。

现在小 C 想知道,在该城市的排水系统中,每个最终排水口会排出多少污水。该城市的排水系统设计科学,管道不会形成回路,即不会发生污水形成环流的情况。

  • 输入格式
    第一个两个用单个空格分隔的整数 \(n, m\)。分别表示排水结点数与接收口数量。
    接下来 \(n\) 行,第 \(i\) 行用于描述结点 \(i\) 的所有排出管道。其中每行第一个整数 \(d_i\)表示其排出管道的数量,接下来 \(d_i\)个用单个空格分隔的整数 \(a_1, a_2, \ldots , a_{d_i}\)依次表示管道的目标排水结点。
    保证不会出现两条起始结点与目标结点均相同的管道。

  • 输出格式
    输出若干行,按照编号从小到大的顺序,给出每个最终排水口排出的污水体积。其中体积使用分数形式进行输出,即每行输出两个用单个空格分隔的整数 \(p,q\),表示排出的污水体积为 \(\dfrac{p}{q}\)。要求 \(p\)\(q\) 互素,\(q = 1\)时也需要输出 \(q\)

constraint

测试点编号 \(n \le\) \(m \le\)
\(1 \sim 3\) \(10\) \(1\)
\(4 \sim 6\) \({10}^3\) \(1\)
\(7 \sim 8\) \({10}^5\) \(1\)
\(9 \sim 10\) \({10}^5\) \(10\)
对于全部的测试点,保证 \(1 \le n \le {10}^5,1 \le m \le 10,0 \le d_i \le 5\).
数据保证,污水在从一个接收口流向一个最终排水口的过程中,不会经过超过 \(10\) 个中间排水结点(即接收口和最终排水口不算在内)。

thoughts&solution

  • 考场上的心路历程

1.浏览完四个题之后回来看第一题应该是可做的,手推了前两个样例想了一下思路。
2.想用链前建边的,但是怕自己写炸改成了纯模拟。
3.看出来了拓扑排序,没敢写,因为觉得自己从\(1\sim n\)遍历的想法没啥问题(事实证明假了,可以卡成0,但是还是有60)
4.实现分数的时候比较复杂,忘记了先除后乘(我一直以为除以gcd会出现问题,啥脑子)
5.写完之后三个样例都过了就感觉很稳,实际上大样例水的一批,那个\(m\)我意识到了没用上但是也没太仔细看题

  • 具体实现
    100pts就是拓扑排序。当然也可以bfs/dfs。

code

  • LG60pts/oitiku90pts/考场
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
#define int long long
int read(){
	int a=0,op=1;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') op=-1;c=getchar();}
	while(c>='0'&&c<='9') a*=10,a+=c^48,c=getchar();
	return a*op;
}
int n,m;
int gcd(int x,int y){
	return !y?x:gcd(y,x%y);
}
struct Node{
	int num;
	int chunum[7],chucnt;
	int d,fz,fm;
}p[maxn];
int ans[maxn],anscnt=0;
int runum[15],rucnt=0;
int vis[maxn],tp,aaa;
int pafz,pafm,ptfz,ptfm,tmpgcd,tmpid;
signed main(){

	n=read(),m=read();
	for(int i=1;i<=n;i++){
		p[i].num=i,p[i].d=read();
		for(int j=1;j<=p[i].d;j++) tp=read(),p[i].chunum[j]=tp,vis[tp]=1;
		if(p[i].d==0) ans[++anscnt]=i;
		p[i].fz=0,p[i].fm=1;
	}
	for(int i=1;i<=n;i++) if(vis[i]==0) runum[++rucnt]=i;
	for(int i=1;i<=rucnt;i++) {
		tmpid=runum[i];
		for(int j=1;j<=p[tmpid].d;j++){
			aaa=p[tmpid].chunum[j];
			//int pafz=p[aaa].fz,pafm=p[aaa].fm,ptfz=p[tmpid].fa,ptfm=p[tmpid].fm;
			p[aaa].fz=1,p[aaa].fm=p[tmpid].d;
		}//p[aaa].shui+=(1/p[tmpid].d);
		p[tmpid].fz=0,p[tmpid].fm=1;
	}
	//for(int i=1;i<=n;i++) printf("%lld--%lld %lld\n",i,p[i].fz,p[i].fm);
	for(int i=1;i<=n;i++){
		//if(p[i].shui==-1) continue;
		for(int j=1;j<=p[i].d;j++){
			aaa=p[i].chunum[j];
			pafz=p[aaa].fz,pafm=p[aaa].fm,ptfz=p[i].fz,ptfm=p[i].fm*p[i].d;
			p[aaa].fz=pafz*ptfm+pafm*ptfz;
			p[aaa].fm=pafm*ptfm;
			tmpgcd=gcd(p[aaa].fz,p[aaa].fm);
			p[aaa].fz/=tmpgcd,p[aaa].fm/=tmpgcd;
			//p[aaa].shui+=(p[i].shui/p[i].d);
		}
		//for(int k=1;k<=n;k++) printf("%lld--%lld--%lld %lld\n",i,k,p[k].fz,p[k].fm);
	}
	for(int i=1;i<=anscnt;i++) {
		printf("%lld %lld\n",p[ans[i]].fz,p[ans[i]].fm);
	}
	return 0;
	
}
  • 100pts
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn=1e6+10;
const int maxm=5e5+10;
const int mod=1e9+7;
#define int __int128
#define inf 0x3f3f3f3f3f
int read(){
	int a=0,op=1;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') op=-1;c=getchar();}
	while(c>='0'&&c<='9') a*=10,a+=c^48,c=getchar();
	return a*op;	
}
int n,m;
int gcd(int a,int b){
	return !b?a:gcd(b,a%b);	
}
int lcm(int a,int b){
	return a/gcd(a,b)*b;	
}
struct node{
	int p,q;
	node(){p=0,q=1;}
	node operator *(const int &rhs) const{
		node res;
		res.p=p,res.q=q*rhs;
		int g=gcd(res.p,res.q);
		res.p/=g,res.q/=g;
		return res;
	}
	node operator +(const node &rhs) const{
		node res;
		res.q=lcm(q,rhs.q);
		res.p+=p*(res.q/q),res.p+=rhs.p*(res.q/rhs.q);
		int g=gcd(res.p,res.q);
		res.p/=g,res.q/=g;
		return res;
	}
}val[maxn];
struct edge{
	int to,nxt;	
}e[maxm];
int cnt,head[maxn],idx[maxn],d[maxn];
void add(int u,int v){
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
	idx[v]++;	
}
queue<int>q;
vector<int>ans;
void topo(){
	for(int i=1;i<=n;i++) if(!idx[i]) q.push(i);
	while(!q.empty()){
		int x=q.front();q.pop();
		if(d[x]) val[x]=val[x]*d[x];
		for(int i=head[x];i;i=e[i].nxt){
			int y=e[i].to;
			val[y]=val[y]+val[x];
			if(--idx[y]==0) q.push(y);	
		}
	}
}
void print(int n){
    if(n > 9) print(n / 10);
    putchar(n % 10 + 48);
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		if(i<=m) val[i].p=1;
		d[i]=read();
		if(d[i]==0) ans.push_back(i);
		for(int j=1,v;j<=d[i];j++) v=read(),add(i,v);
	}
	topo();
	for(int i=0;i<ans.size();i++) print(val[ans[i]].p),printf(" "),print(val[ans[i]].q),printf("\n");
	return 0;
}
posted @ 2020-12-19 23:24  齐思钧  阅读(527)  评论(0)    收藏  举报