概率期望的更多应用
关于概率期望的更多应用问题(更新中)
1.与方差有关的,可以推导出D(x)=E(x的平方)-E平方(X)
然后就是例题:「重庆市NOIP模拟赛」好路线 (dp)
dp[i][j][k]表示到(i,j)这个点时,前面路径上h的和是k(就相当于美剧了所有路径)此时这条路径上h的平方和最小值
为什么这么设?
E(x)在此时就是E(h),E相当于平均数
那么E(h)=(k/(i+j-1)),两边平方就可以得到公式中的减数
那么dp为什么要存平方和呢?
E(x方)=E(h方)=h平方和的平均数=dp/(i+j-1)
那dp为什么要存最小值呢?因为我枚举k,相当于减数已经确定,让被减数,也就是dp最小的情况下,这样相减得到的答案最小,也就是方差最小了
那最后只需要美剧(dp[n][m][i])就可以了(用上式计算取min即可)
当然最后答案乘上了(n+m-1)的平方,那么就是dp[n][m][i](n+m-1)-ii就是了
附上评测链接(bz的才有福利哦)
http://222.180.160.110:1024/problem/9931
#include<bits/stdc++.h>
using namespace std;
int h[55][55];
int dp[55][55][12505];//走到i,j时,h和(利用这个除以路长度再平方就是E方(x),存的是h方之和的最小值
int main(){
ios::sync_with_stdio(false);
int n,m;
cin >> n >> m;
int ma=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin >> h[i][j];
ma=max(ma,h[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<=ma*(n+m-1);k++){
dp[i][j][k]=0x3f3f3f3f;
}
}
}
dp[1][1][h[1][1]*1]=h[1][1]*h[1][1];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<=ma*(n+m-1);k++){
if(dp[i][j][k]==0x3f3f3f3f){
continue;//这个状态转移不到
}
int nx=i+1;
int ny=j;
dp[nx][ny][k+h[nx][ny]]=min(dp[nx][ny][k+h[nx][ny]],dp[i][j][k]+h[nx][ny]*h[nx][ny]);
nx=i;
ny=j+1;
dp[nx][ny][k+h[nx][ny]]=min(dp[nx][ny][k+h[nx][ny]],dp[i][j][k]+h[nx][ny]*h[nx][ny]);
}
}
}
int mii=0x3f3f3f3f;
for(int i=0;i<=ma*(n+m-1);i++){
if(dp[n][m][i]==0x3f3f3f3f){
continue;
}
mii=min(mii,(n+m-1)*dp[n][m][i]-i*i);//最后要求求(n+m-1) 的平方乘上他,就可以化简了
}
cout<<mii;
}
例题2:「NOIP 2021」方差 ( variance )
这是一个细节满满的题,一定要重视我//的部分以及错误的批注
#include<bits/stdc++.h>
using namespace std;
#define int long long
/*
这道题分析后发现,这个数组的变换中,差分数组成分不变,但顺序变了。
所以差分数组是可以随意排序的;可以看一下样例哦
问题转换为:这个数组的差分数组(乱序)所有前缀段的方差最小
那么大概该怎么选择这个呢(怎么排序这个差分数组呢?)
(老师上课没有详细的证明,但有感性的证明,用的是函数图像)
注意,由于差分数组有可能出现负数,所以不能单纯的排序后把前面几项视为0删除
*/
const int inf=1e18;
bool cmp(int x,int y){
return x>y;
}
int num[10405];
int cf[10405];
int dp[15][540005];//考虑前i个差分时num的和为j时的num平方和 ,显然是可以辗转的
signed main(){
freopen("variance.in","r",stdin);
freopen("variance.out","w",stdout);
ios::sync_with_stdio(false);
int n;
cin >> n;
int mx=-inf;
for(int i=1;i<=n;i++){
cin >> num[i];
cf[i]=num[i]-num[i-1];
mx=max(num[i],mx);
}
sort(cf+2,cf+1+n);
// n-=cnt;//把0的部分全部排除掉,因为对dp完全没贡献 ,这样写是错的,注释给出了问题所在
// dp[1][?]
for(int i=0;i<=mx*n;i++) {
dp[0][i]=inf;
dp[1][i]=inf;
}
dp[1][0]=0;
int now=0;
int p=1,q;
for(int i=2;i<=n;i++){
now+=cf[i];
if(cf[i]==0){
// for(int j=0;j<=n*mx;j++){
// dp[i%2][j]=dp[(i+1)%2][j]; //--------------做的原因是如果直接continue,这一次本来两边可以乱放就变为了这次两边都不能放 (44分原因) ,所以要“复制”
// } 但是这么做的话肯定TLE,所以我还是选择把所有的0给踢出去 ,或者是利用其他方法再辗转 ,这里用的后者,引入了p,q
continue;
}
q=p;
p=q^1;//这样就可以避免tle和“复制”不了两个问题了
for(int j=0;j<=n*mx;j++){
dp[p][j]=inf;
}
for(int j=0;j<=n*mx;j++){
if(dp[q][j]==inf){//上一次没有状态,这次不进行计算
continue;
}
//放在前面
int s=j+(i-1)*cf[i];
dp[p][s]=min(dp[p][s],1ll*cf[i]*cf[i]*(i-1)+dp[q][j]+2ll*cf[i] *j);
//放在后面,和前面那道题差不多
s=j+now;
dp[p][s]=min(dp[p][s], dp[q][j]+1ll*now*now);
}
}
int ans=inf;
for(int i=0;i<=n*mx;i++){
if(dp[p][i]==inf){
continue;
}
ans=min(ans,n*dp[p][i]-i*i);
}
cout<<ans;
}