QOJ349 彩绘 题解
QOJ349 彩绘
给定 \(n\) 个三元组 \((r_i,g_i,b_i)\),每次可以合并相邻的两个三元组为 \((\frac{r_i+r_{i+1}}{2},\frac{g_i+g_{i+1}}{2},\frac{b_i+b_{i+1}}{2})\),问最终合并成一个三元组之后,\((r,g,b)\) 的期望对 \(998244353\) 取模,\(n \le 10^5,r,g,b\le 255\)。
考虑求出每个位置的期望贡献系数,发现如果它发生了 \(k\) 次合并,其系数就乘以 \(\frac{1}{2^k}\),由于左右两边的的合并次数相互独立,所以考虑分开算。左侧有 \(i-1\) 个空,所以会发生 \(i-1\) 次合并,右侧则是 \(n-i\) 次。
考虑给每个空一个编号,编号是它是第几个被合并的空,那么 \(i\) 这个数的贡献系数,就是这个编号序列的后缀最大值个数,因为一个合并能影响到 \(i\) 只能是其后面的空都被合并过了,如果是右侧的话应该是前缀最小值个数,计算方式都是一样的。
设 \(f_i\) 表示有 \(i\) 个空时的贡献系数,考虑怎么转移,我们把第一个被合并的那个缝隙单独考虑,如果它在最后一个位置,那后缀最大值的个数加 \(1\),贡献就加 \(\frac{1}{2}f_{i-1}\)。如果不是最后一个位置,那就没有新的贡献,加上 \((i-1)\times f_{i-1}\)。
得到了每个长度的贡献系数以后,单独每个位置考虑,其期望贡献系数就为 \(\frac{f_{i-1}}{(i-1)!} \times \frac{f_{n-i}}{(n-i)!}\),再乘上对应的值即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n;
const int N = 1e5+10,mod=998244353;
int r[N],g[N],b[N],fac[N],inv2,invf[N],f[N],ans[3];
int qpow(int a,int b){
int res=1;
while(b){
if(b&1)res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
int C(int n,int m){
if(n<m||m<0)return 0;
return fac[n]%mod*invf[m]%mod*invf[n-m]%mod;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>r[i]>>g[i]>>b[i];
}
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=(fac[i-1]*i)%mod;
}
inv2=qpow(2,mod-2);
invf[n]=qpow(fac[n],mod-2);
for(int i=n-1;i>=0;i--){
invf[i]=(invf[i+1]*(i+1))%mod;
}
f[0]=1;
for(int i=1;i<=n;i++){
f[i]=((i-1)%mod*f[i-1]%mod+inv2%mod*f[i-1])%mod;
}
for(int i=1;i<=n;i++){
int e=f[i-1]%mod*invf[i-1]%mod*f[n-i]%mod*invf[n-i]%mod;
ans[0]=(ans[0]+e%mod*r[i]%mod)%mod;
ans[1]=(ans[1]+e%mod*g[i]%mod)%mod;
ans[2]=(ans[2]+e%mod*b[i]%mod)%mod;
}
cout<<ans[0]<<" "<<ans[1]<<" "<<ans[2];
return 0;
}

浙公网安备 33010602011771号