版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89453188
【题目】
CF
有一个长度为
的数列
,有
个操作,每个操作有
的概率给
加一,所有操作的区间仅有完全包含和不相交关系。求所有操作后
中最大值的期望。
【解题思路】
题目给出的限制实际上是一棵树结构,完全包含的区间外层为父亲,内层为儿子。
观察到操作数比较少,也就是说最后加的权值比较小,考虑针对这个东西来 。
不妨令 表示 子树操作结束后, 点代表的区间最大值 的概率,其中 表示原区间最大值。那么若当前操作不执行,只需要所有子树中最大值均 的概率和。否则需要所有子树中最大值均 的概率和,那么可以得到:
复杂度
【参考代码】
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef double db;
const int N=1e5+10,M=5010;
int n,m,Log[N],fc[20],st[18][N];
db f[M][M];
vector<int>G[M];
struct data
{
int l,r,mx;db p;
data(int _l=0,int _r=0,int _m=0,db _p=0):l(_l),r(_r),mx(_m),p(_p){}
}q[M];
bool cmp(const data&A,const data&B){return A.l==B.l?A.r>B.r:A.l<B.l;}
void dfs(int x)
{
db p=1;
for(auto v:G[x]) dfs(v);
for(auto v:G[x]) p*=f[v][q[x].mx-q[v].mx];
f[x][0]=(1-q[x].p)*p;
for(int i=1;i<=m;++i)
{
db p1=1,p2=1;
for(auto v:G[x]) p1*=f[v][min(q[x].mx+i-q[v].mx-1,m)],p2*=f[v][min(q[x].mx+i-q[v].mx,m)];
f[x][i]=q[x].p*p1+(1-q[x].p)*p2;
}
}
int query(int l,int r)
{
int k=Log[r-l+1];
return max(st[k][l],st[k][r-fc[k]+1]);
}
int main()
{
#ifdef Durant_Lee
freopen("CF494C.in","r",stdin);
freopen("CF494C.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&st[0][i]);
fc[0]=1;for(int i=1;i<20;++i) fc[i]=fc[i-1]<<1;
for(int i=2;i<=n;++i) Log[i]=Log[i>>1]+1;
for(int j=1;j<17;++j) for(int i=1;i+fc[j]-1<=n;++i)
st[j][i]=max(st[j-1][i],st[j-1][i+fc[j-1]]);
for(int i=1;i<=m;++i)
{
scanf("%d%d%lf",&q[i].l,&q[i].r,&q[i].p);
q[i].mx=query(q[i].l,q[i].r);
}
q[++m]=data(1,n,query(1,n),0);
sort(q+1,q+m+1,cmp);
for(int i=2;i<=m;++i) for(int j=i-1;j;--j)
if(q[j].l<=q[i].l && q[i].r<=q[j].r) {G[j].pb(i);break;}
dfs(1);db ans=f[1][0]*q[1].mx;
for(int i=1;i<=m;++i) ans+=(f[1][i]-f[1][i-1])*(q[1].mx+i);
printf("%lf\n",ans);
return 0;
}