CF494C Helping People

\(CF494C\ \ Helping People\)

题目描述

给一个序列 \(a_1,a_2,a_3,\dots a_n\)\(m\) 次操作,每次可将区间 \([a_i,b_i]\) 加上 \(1\) ,操作成功的概率是 \(p_i\) ,求最后序列中最大值的期望。

对于两个区间 \([a,b],[c,d]\) ,保证 以下条件之一成立:

  • 这两个段完全不相交。更正式地说,要么 \(a ≤ b < c ≤ d\) ,要么 \(c ≤ d < a ≤ b\)
  • 两个段中的一个包含在另一个内。更正式地说,要么 \(a ≤ c ≤ d ≤ b\) ,要么 \(c ≤ a ≤ b ≤ d\)

思路分析

因为任意两个区间,要么完全不相交,要么相包含,所以我们用一个 \(nb\) 的东西——树!

考虑跑树形 \(DP\) ,设 \(dp_{x,i}\) 表示节点 \(x\) 区间中 \(\leq i\) 的概率,类似于前缀和。但是 \(a_i \leq 10^9\),第二维开不下。但是我们发现,\(m\) 次操作最多增加 \(m\) ,所以我们将第二维开到 \(m\) ,类似于存一个变化量。

对于转移节点 \(x\):

  • \(x\)\(p_x\) 的概率 \(+1\) ,那么对应的儿子 \(y\) 就应为 \(i+x_{maxn}-y_{maxn}-1\) ,其中 \(maxn\) 是区间最大值,领悟一下就是从 \(y_{maxn}\) 变成 \(x_{maxn}\)

\[dp_{x,i}+=p_x\times \prod_{y\in son_x}dp_{y,i+x_{maxn}-y_{maxn}-1} \]

  • \(x\)又有 \(1-p_x\) 的概率不变,同理:

\[dp_{x,i}+=(1-p_x)\times \prod_{y\in son_x}dp_{y,i+x_{maxn}-y_{maxn}} \]

  • 所以最终的转移方程:

\[dp_{x,i}=p_x\times \prod_{y\in son_x}dp_{y,i+x_{maxn}-y_{maxn}-1}+(1-p_x)\times \prod_{y\in son_x}dp_{y,i+x_{maxn}-y_{maxn}} \]

另外对于求区间最大值,可以用 \(st\) 表查询 (我是废物,st表打假了调半天)

\(AC\ \ code\)

#include<bits/stdc++.h>
using namespace std;
#define read read()
#define pt puts("")
inline int read
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}
    while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return f*x;
}
#define N 100010
#define M 5010
int n,m;
int a[N];
int son[M][M];
int sonsum[M];
struct SPX{
    int l,r;
    double p;
    int maxn;
}spx[M];

bool cmp(SPX A,SPX B){
    if(A.l==B.l)  return A.r>B.r;
    return A.l<B.l;
}

int st[N][20];
int Max(int l,int r){
    int k=log2(r-l+1);
    return max(st[l][k],st[r-(1<<k)+1][k]);
}
int Maxn;
double dp[M][M];
double ans;
void dfs(int x)
{
    int y;
    for(int i=1;i<=sonsum[x];i++){
        y=son[x][i];
        dfs(y);
    }
    dp[x][0]=1-spx[x].p;
    for(int i=1;i<=sonsum[x];i++){
        y=son[x][i];
        dp[x][0]*=dp[y][spx[x].maxn-spx[y].maxn];
    }
    for(int i=1;i<=m;i++){
        double p1=spx[x].p;
        double p2=1-p1;
        for(int j=1;j<=sonsum[x];j++){
            y=son[x][j];
            p1*=dp[y][min(i+spx[x].maxn-spx[y].maxn-1,m)];
            p2*=dp[y][min(i+spx[x].maxn-spx[y].maxn,m)];
        }
        dp[x][i]=p1+p2;
    }
}

signed main()
{
    n=read;m=read;
    for(int i=1;i<=n;i++){
        a[i]=read;st[i][0]=a[i];
        Maxn=max(Maxn,a[i]);
    }
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    spx[1]=SPX{1,n,0.0,Maxn};m++;
    for(int i=2;i<=m;i++)
    {
        spx[i].l=read;
        spx[i].r=read;
        scanf("%lf",&spx[i].p);
        spx[i].maxn=Max(spx[i].l,spx[i].r);
    }
    sort(spx+1,spx+m+1,cmp);
    for(int i=2;i<=m;i++)
        for(int j=i-1;j>=1;--j)
            if(spx[j].l<=spx[i].l && spx[i].r<=spx[j].r){
                son[j][++sonsum[j]]=i;
                break;
            }
    dfs(1);
    ans=dp[1][0]*Maxn;
    for(int i=1;i<=m;i++)
        ans+=(dp[1][i]-dp[1][i-1])*(i+Maxn);
    printf("%.9lf",ans);
    return 0;
}
posted @ 2024-03-28 08:33  lty_ylzsx  阅读(14)  评论(0编辑  收藏  举报