题解 排水系统

传送门

这题把孩子整自闭了

考场思路是维护一个 \(f_i\) 表示到位置 \(i\),还未出现过堵塞边的期望流量
再维护一个 \(g_i\) 表示到 \(i\) 已经出现堵塞边的期望流量
但实现难点在于要维护一个出现了堵塞边但这条边不是点 \(i\) 的祖先的概率
非常难写

于是题解折腾了我半天
发现这道题实际上是在对所有可行方案求和
于是把期望都抛开
现在我们想求断开每条边的概率乘上断开每条边的价值
肯定不能做 \(k\) 次拓扑排序,现在考虑怎么在一次拓扑排序中将这个总和求出来
发现断的边不同时DAG的形态是不一样的,不好处理
于是尝试将DAG的形态固定下来
发现因为一次只能断一条边 \((x, y)\),所以经过 \(x\) 的流量是固定的,变化的只是其子节点的流量
于是尝试在保持DAG形态不变的前提下(不断开边 \((x, y)\))通过调整流量达到断开的效果
发现要让 \(x\) 其它节点的流量增加一些,\(y\) 的流量减少一些
可以直接在 \(x, y\) 的流量上做这个加减

关于这个做法的一些正确性证明:
其实也没什么好证的只是我脑残了
问题主要在于怎么保证每次断边的影响是独立的
我想假了主要是因为总觉得祖先节点的修改会影响到在后代节点统计修改时的答案
但其实每个修改加上的偏移量都是用不断边的流量计算出来的
而且这个修改的方式只是加减
所以不同断边之间互不影响

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF: *p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, r, k;
int head[N], cnt[N], deg[N], size;
ll sum, invs, inv[N];
const ll mod=998244353;
struct edge{int to, from, next; ll a; bool del;}e[N];
inline void add(int s, int t, ll w) {e[++size].to=t; e[size].from=s; e[size].a=w; e[size].del=0; e[size].next=head[s]; head[s]=size;}
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
inline ll qinv(ll a) {return qpow(a, mod-2);}
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}

namespace force{
	ll in[N], ans[N];
	queue<int> q;
	void calc() {
		for (int i=1; i<=n; ++i) cnt[i]=0, in[i]=0;
		for (int i=1; i<=size; ++i) ++cnt[e[i].to];
		for (int i=1; i<=m; ++i) if (!cnt[i]) q.push(i), in[i]=1; //, cout<<"push: "<<i<<endl;
		int u;
		while (q.size()) {
			u=q.front(); q.pop();
			// cout<<"u: "<<u<<endl;
			int out=0;
			for (int i=head[u]; ~i; i=e[i].next) if (!e[i].del) ++out;
			ll pre=in[u]*inv[out]%mod;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (!e[i].del) md(in[v], pre);
				if (--cnt[v]==0) q.push(v);
			}
		}
	}
	void solve() {
		for (int i=1; i<=size; ++i) if (e[i].a) {
			e[i].del=1;
			calc();
			ll t=e[i].a*invs%mod;
			for (int j=n-r+1; j<=n; ++j) ans[j]=(ans[j]+t*in[j])%mod;
			e[i].del=0;
		}
		for (int i=n-r+1; i<=n; ++i) printf("%lld%c", ans[i], " \n"[i==n]);
		exit(0);
	}
}

namespace task1{
	ll in[N], ans[N], dlt[N];
	queue<int> q;
	void calc() {
		for (int i=1; i<=n; ++i) cnt[i]=0, in[i]=0;
		for (int i=1; i<=size; ++i) ++cnt[e[i].to];
		for (int i=1; i<=m; ++i) if (!cnt[i]) q.push(i), in[i]=1; //, cout<<"push: "<<i<<endl;
		int u;
		while (q.size()) {
			u=q.front(); q.pop();
			// cout<<"u: "<<u<<endl;
			int out=0; ll ps=0;
			for (int i=head[u]; ~i; i=e[i].next) ++out, dlt[e[i].to]=0, ps=(ps+e[i].a*invs)%mod;
			// cout<<"u: "<<u<<' '<<ps<<endl;
			// cout<<"in: "<<(in[u]%mod+mod)%mod<<endl;
			// ll pre=in[u]*inv[out]%mod, sum=0;
			// cout<<"ps: "<<ps<<endl;
			ll sum=(1-ps)*in[u]%mod*inv[out]%mod;
			// cout<<"sum: "<<sum<<endl;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				sum=(sum+e[i].a*invs%mod*in[u]%mod*inv[out-1])%mod;
				dlt[v]=e[i].a*invs%mod*in[u]%mod*inv[out-1];
			}
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				in[v]=(in[v]+sum-dlt[v])%mod;
				if (--cnt[v]==0) q.push(v);
			}
		}
	}
	void solve() {
		calc();
		for (int i=n-r+1; i<=n; ++i) printf("%lld%c", (in[i]%mod+mod)%mod, " \n"[i==n]);
		exit(0);
	}
}

namespace task2{
	ll in[N], ans[N], dlt[N], at[N];
	queue<int> q;
	void solve() {
		for (int i=1; i<=n; ++i) cnt[i]=0, in[i]=0;
		for (int i=1; i<=size; ++i) ++cnt[e[i].to];
		for (int i=1; i<=m; ++i) if (!cnt[i]) q.push(i), in[i]=1;
		while (q.size()) {
			int u=q.front(); q.pop();
			int out=0; ll ps=0;
			for (int i=head[u]; ~i; i=e[i].next) ++out, dlt[e[i].to]=0, ps=(ps+e[i].a*invs)%mod;
			ll pre=in[u]*inv[out]%mod;
			ll sum=at[u]*in[u]%mod*inv[out]%mod;
			ll add=0;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				sum=(sum+e[i].a*invs%mod*in[u]%mod*inv[out-1])%mod;
				add=(add+e[i].a*invs)%mod;
				dlt[v]=e[i].a*invs%mod*in[u]%mod*inv[out-1]%mod;
			}
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				ans[v]=(ans[v]+sum-dlt[v]+ans[u]*inv[out]%mod)%mod;
				md(in[v], pre); at[v]=(at[v]+add-e[i].a*invs)%mod;
				if (--cnt[v]==0) q.push(v);
			}
		}
		for (int i=n-r+1; i<=n; ++i) printf("%lld%c", (ans[i]%mod+mod)%mod, " \n"[i==n]);
		exit(0);

		#if 0
		cout<<"ans: "; for (int i=1; i<=n; ++i) cout<<(ans[i]+mod)%mod<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) cnt[i]=0;
		for (int i=1; i<=size; ++i) ++cnt[e[i].to];
		for (int i=1; i<=m; ++i) if (!cnt[i]) q.push(i);
		while (q.size()) {
			int u=q.front(); q.pop();
			int out=0;
			// cout<<"u: "<<u<<' '<<(ans[u]+mod)%mod<<endl;
			for (int i=head[u]; ~i; i=e[i].next) ++out;
			ll pre=ans[u]*inv[out]%mod;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				md(ans[v], pre);
				if (--cnt[v]==0) q.push(v);
			}
		}
		for (int i=n-r+1; i<=n; ++i) printf("%lld%c", (ans[i]%mod+mod)%mod, " \n"[i==n]);
		exit(0);
		#endif
	}
}

namespace task{
	ll f[N], ans[N];
	queue<int> q;
	void solve() {
		for (int i=1; i<=n; ++i) cnt[i]=0;
		for (int i=1; i<=size; ++i) ++cnt[e[i].to];
		for (int i=1; i<=m; ++i) if (!cnt[i]) q.push(i), f[i]=1;
		int u;
		while (q.size()) {
			u=q.front(); q.pop();
			int out=0;
			ll pre=f[u]*inv[deg[u]]%mod;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				md(f[v], pre);
				if (--cnt[v]==0) q.push(v);
			}
		}
		for (int i=1; i<=k; ++i) {
			ll p=e[i].a*invs%mod;
			ans[e[i].from]=(ans[e[i].from]+f[e[i].from]*inv[deg[e[i].from]-1]%mod*p)%mod;
			ans[e[i].to]=(ans[e[i].to]-f[e[i].from]*inv[deg[e[i].from]-1]%mod*p)%mod;
		}
		// cout<<"ans: "; for (int i=1; i<=n; ++i) cout<<ans[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) cnt[i]=0;
		for (int i=1; i<=size; ++i) ++cnt[e[i].to];
		for (int i=1; i<=m; ++i) if (!cnt[i]) q.push(i), ans[i]+=1;
		while (q.size()) {
			u=q.front(); q.pop();
			// cout<<"u: "<<u<<' '<<ans[u]<<endl;
			ll pre=ans[u]*inv[deg[u]]%mod;
			// cout<<"pre: "<<pre<<endl;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				ans[v]=(ans[v]+pre)%mod;
				if (--cnt[v]==0) q.push(v);
			}
		}
		for (int i=n-r+1; i<=n; ++i) printf("%lld%c", (ans[i]%mod+mod)%mod, " \n"[i==n]);
		exit(0);
	}
}

signed main()
{
	freopen("water.in", "r", stdin);
	freopen("water.out", "w", stdout);

	n=read(); m=read(); r=read(); k=read();
	memset(head, -1, sizeof(head));
	int unzero=0;
	for (int i=1,u,v,w; i<=k; ++i) {
		u=read(); v=read(); w=read();
		add(u, v, w); sum=(sum+w)%mod; ++deg[u];
		if (w) ++unzero;
	}
	invs=qinv(sum);
	inv[0]=inv[1]=1;
	for (int i=2; i<N; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	// cout<<"inv: "; for (int i=1; i<=n; ++i) cout<<inv[i]<<' '; cout<<endl;
	// if (unzero<=5000) force::solve();
	// else task1::solve();
	task::solve();

	return 0;
}
posted @ 2021-11-05 06:23  Administrator-09  阅读(0)  评论(0编辑  收藏  举报