CF1172C Nauuo and Pictures 题解

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] 转移自三个地方:

  1. \(\frac{x}{a+b}\) 的概率转移自 f[x+1][i-1][a+1][b]
  2. \(\frac{a-x}{a+b}\) 的概率转移自 f[x][i-1][a+1][b]
  3. \(\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;
}
原文地址:https://www.cnblogs.com/pealfrog/p/15088930.html