[题解] CF1854C Expected Destruction
CF1854C Expected Destruction *2500
tag:概率期望
题目大意
给出一个包含 \(n\) 个元素 \(s_{1\cdots n}\) 的集合 \(S\),每次操作会等概率随机一个 \(S\) 中的数字进行如下操作:
- 设选中的数字为 \(x\),将 \(x\) 从 \(S\) 中删去
- 若 \(x+1\le m\) 且 \(x+1\) 不在 \(S\) 中,则将 \(x+1\) 加入到 \(S\) 中
问将 \(S\) 变成空集的期望操作次数 \(\bmod 10^9+7\)
\(1\le n\le m\le 500\),\(s_i\) 单增,\(\texttt{1s,256M}\)
思路
- 由期望的线性性,可以尝试将每个元素分开来看,求出每个元素撞上 \(x+1\) 所需要的期望操作次数
- 但问题是可能 \(x\) 再撞上 \(x+1\) 之前,\(x+1\) 已经撞上另一个更大的数字消失了,此时我们认为并不是 \(x+1\) 消失,而是那个更大的数字消失,除非移动到了 \(m+1\),这样 \(x+1\) 就永远不会消失了
- 因此问题变成了只考虑 \(x\) 与 \(x+1\) 之间的关系,可以设
dp[i][j]表示前一个在 \(i\),后一个在 \(j\) 的期望移动次数,那么边界条件为dp[i][i]=0以及dp[i][m+1]=m+1-i,转移分两种情况,\(i,j\) 被选中的概率均为 \(\frac{1}{2}\),那么可以得到转移dp[i][j]=((dp[i+1][j]+1)+dp[i][j+1])/2就可以求出所有的dp值了 - 最终答案即为所有
dp[s[i]][s[i+1]]的和(最后添加一个 \(s_{n+1}=m+1\)) - 时空复杂度 \(O(m^2)\)
#include<bits/stdc++.h>
using namespace std;
const int N=505,mod=1e9+7,Inv2=(mod+1)/2;
int n,m,ans,dp[N][N],a[N];
int main(){
scanf("%d%d",&n,&m);
for (int i=1; i<=m+1; i++) dp[i][m+1]=m+1-i,dp[i][i]=0;
for (int i=m; i>=1; i--)
for (int j=m; j>i; j--)
dp[i][j]=1ll*(dp[i+1][j]+1+dp[i][j+1])*Inv2%mod;
for (int i=1; i<=n; i++) scanf("%d",&a[i]); a[n+1]=m+1;
for (int i=1; i<=n; i++) ans=(ans+dp[a[i]][a[i+1]])%mod;
printf("%d\n",ans);
}

浙公网安备 33010602011771号