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();
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18555478