SS241119C. 甜果(sugar)

SS241119C. 甜果(sugar)

题意

\(n\) 个人,每个人初始有 \(a_i\) 颗糖果,有 \(n\) 个事件,事件 \(i\) 是如果 \(a_i > a_{b_i}\),那么 \(a_i' : = a_i + w_i\)

问所有事件以随机的排列的顺序依次发生后,每个人的期望糖果数量。

思路

即求每个事发生的概率 \(p_i\),那么 \(ans_i = a_i + p_i w_i\)

考虑什么时候 \(p_i\) 会发生,什么时候不会发生。

\(t_i\) 表示操作 \(i\) 发生的时间。

  • \(a_i \le a_{b_i}\) 时,\(p_i = 0\)
  • \(a_i > a_{b_i}+w_{b_i}\) 时,\(p_i=1\)
  • \(a_{b_i} < a_i \le a_{b_i}+w_i\) 时,如果 \(p_{b_i} =1 且 t_{b_i} < t_i\)\(p_i=0\),否则 \(p_i = 1\)

这启发我们对于第三种情况,从 \(i\)\(b_i\) 连边。这样我们就会连出若干棵树。而每个 \(p_i\) 只和与它同一条链的点,进一步地,只和链上在它后面的那些点是否发生有关。

对于一条链,上面的点 \(x_0\),我们扔掉在它前面的那些点,使 \(x_0\) 成为链头,后面依次是 \(x_1 \sim x_{len-1}\)

如果 \(t_{x_{j+1}} > t_{x_j}\),那么 \(p_{x_j}=1\),因此我们枚举最小的 \(j\),满足 \(t_{x_{j+1}} > t_{x_j}\),那么有 \(p_{x_j}=1\),那么 \(x_{j+1} \sim x_{len-1}\)\(p\) 是多少,对 \(p_{x_0}\) 都没有影响了。

因此有 \(t_{x_0} > t_{x_1} > \cdots > t_{x_j} < t_{x_{j+1}}\)

\(j\) 是偶数的时候 \(p_{x_0}=1\),满足 \(t_{x_0 \sim x_j}\) 降序的方案数是 \(\frac{n!}{(j+1)!}\),这个方案还需要减去不满足 \(t_{x_j} < t_{x_j+1}\) 的情况,即 \(\frac{n!}{(j+2)!}\)

需要注意一下边界细节。

我们使 \(len\) 减去 \(1\)

因此 \(p_{x_0} = \frac{1}{n!}\sum_{j=0}^{len} (-1)^j \frac{n!}{j!} = \sum_{j=0}^{len}\frac{(-1)^j}{j!}\)

这个长成错排公式的样子。可以递推预处理错排公式,然后对每个 \(x_0\) 求概率。时间复杂度 \(O(n)\)

code

讨厌细节。

跑得飞快,跑到目前最优解去了。

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace serendipity {
	#define isdigit(x) (x>='0'&&x<='9')
	#define gc getchar_unlocked
	#define pc putchar_unlocked
	template <typename T>
	void read(T &x) {
		x=0;
		char ch=gc();
		for(;!isdigit(ch);ch=gc());
		for(;isdigit(ch);ch=gc()) x=(x<<3)+(x<<1)+(ch^48);
	}
	template <typename T>
	void write(T x,char ch) {
		static int st[40];
		int top=0;
		do {
			st[top++]=x%10;
			x/=10;
		}while(x);
		while(top) pc(st[--top]^48);
		pc(ch);
	}
	constexpr int N=5e5+7,mod=1e9+7;
	int add(int a,int b) { return a+b>=mod ? a+b-mod : a+b; }
	void _add(int &a,int b) { a=add(a,b); }
	int t,n,a[N],b[N],w[N];
	int len[N],ans[N],f[N],p[N];
	int jc[N],inv[N];
	ll ksm(ll a,ll b=mod-2) {
		ll s=1;
		while(b) {
			if(b&1) s=s*a%mod;
			a=a*a%mod;
			b>>=1;
		}
		return s;
	}
	void dfs(int u) {
		if(ans[u]||len[u]) {
			return;
		}
		dfs(b[u]);
		if(ans[b[u]]==2) ans[u]=1;
		else {
			ans[u]=0;
			if(ans[b[u]]==1) len[u]=2;
			else len[u]=len[b[u]]+1;
			p[u]=1ll*add(jc[len[u]],mod-f[len[u]])*inv[len[u]]%mod;
		}
	}
	void main() {
		read(t);
		while(t--) {
			read(n);
			jc[0]=1;
			rep(i,1,n) jc[i]=1ll*jc[i-1]*i%mod;
			inv[n]=ksm(jc[n]);
			per(i,n-1,0) inv[i]=1ll*inv[i+1]*(i+1)%mod;
			f[2]=1;
			rep(i,3,n) f[i]=1ll*(i-1)*add(f[i-1],f[i-2])%mod;
			memset(len+1,0,sizeof(int)*n);
			memset(ans+1,0,sizeof(int)*n);
			rep(i,1,n) read(a[i]);
			rep(i,1,n) read(b[i]);
			rep(i,1,n) read(w[i]);
			rep(i,1,n) {
				if(a[i]<=a[b[i]]) ans[i]=2;
				else if(a[i]>a[b[i]]+w[b[i]]) ans[i]=1;
			}
			rep(i,1,n) {
				dfs(i);
				if(ans[i]==2) write(a[i],' ');
				else if(ans[i]==1) write(add(a[i],w[i]),' ');
				else write(add(a[i],1ll*w[i]*p[i]%mod),' ');
			}
			pc('\n');
		}
	}
}
int main() {
	#ifdef LOCAL
	freopen("my.out","w",stdout);
	#else 
	freopen("sugar.in","r",stdin);
	freopen("sugar.out","w",stdout);
	#endif
	serendipity :: main();
}
posted @ 2024-11-19 19:48  liyixin  阅读(22)  评论(0编辑  收藏  举报