Link.
Codeforces C1
Codeforces C2
Luogu C1
Luogu C2
Description.
每张照片有一个权值 \(w_i\),每次第 \(x\) 张照片有 \(\frac{w_x}{\sum_{i=1}^nw_i}\) 的概率被展示。
每次,如果这张照片被喜欢,那 \(w_i\leftarrow w_i+1\),否则 \(w_i\leftarrow w_i-1\)。
问 \(m\) 次后每张照片的权值。
C1
\(n\le 50,m\le 50,w_i\le 50\)
C2
\(n\le 3\times 10^5,m\le 3000\)
Solution of C1.
考虑一个 f[x][i][a][b]
表示初始权值为 \(x\) 的被喜欢的照片,经过 \(i\) 次后期望是什么。
其中 \(a\) 表示当前喜欢照片总权值,\(b\) 表示当前不喜欢照片的总权值。
每次转移,f[x][i][a][b]
转移自三个地方:
- 以 \(\frac{x}{a+b}\) 的概率转移自
f[x+1][i-1][a+1][b]
- 以 \(\frac{a-x}{a+b}\) 的概率转移自
f[x][i-1][a+1][b]
- 以 \(\frac{b}{a+b}\) 的概率转移自
f[x][i-1][a][b-1]
同理,设一个 g[x][i][a][b]
表示不被喜欢的照片
直接大力转移,复杂度很高,但据说能 AC?
Solution of C2
发现一个性质:\(f[x][i][a][b]=f[1][i][a][b]\times x\),严谨证明详见
感性证明就是初始权值都翻倍了,答案必定翻倍。
同时,观察转移,我们发现 \(i-b+a\) 一定是定值,可以压掉一维。
然后就做完了,复杂度 \(O(n+m^2)\)。
我们用 \(f'[a][b]\) 表示 \(f[1][m-a-b][tota+a][totb-b]\)
Coding.
点击查看 C2 代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了……{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=1;
for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
if(f) x=-x;
}/*}}}*/
const int P=998244353;int n,m,tota,totb,tot;
int w[200005],f[3005][3005],g[3005][3005];char a[200005];
inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
int main()
{
read(n),read(m);for(int i=1;i<=n;i++) read(a[i]);
for(int i=1,x;i<=n;i++) read(x),w[i]=x,(a[i]?tota:totb)+=x,tot+=x;
for(int i=m;~i;i--)
{
f[i][m-i]=g[i][m-i]=1;
for(int j=min(m-i-1,totb);j>=0;j--)
f[i][j]=(1ll*(tota+i+1)*f[i+1][j]+1ll*(totb-j)*f[i][j+1])%P*ksm(i-j+tot)%P,
g[i][j]=(1ll*(tota+i)*g[i+1][j]+1ll*(totb-j-1)*g[i][j+1])%P*ksm(i-j+tot)%P;
}
for(int i=1;i<=n;i++) printf("%lld\n",1ll*w[i]*(a[i]?f[0][0]:g[0][0])%P);
return 0;
}