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

浙公网安备 33010602011771号