标签:另一个 rod algo ace 就是 结构 printf [1] 表示
题意:有$n$个穷人,每个穷人有$a_i$的钱,有一个富人决定做$q$次捐赠$(l_i,r_i,p_i)$,表示他有$p_i$的概率给$[l_i,r_i]$的人捐$1$的钱,捐赠的价值为捐赠后最富的人拥有的钱数,问捐赠的价值的期望,保证给出的$[l_i,r_i]$要么相离要么一个包含另一个
捐赠区间是树的结构,先把树建出来,把区间按$l$从小到大排序,若$l$相同则按$r$从大到小,那么一个区间的父亲就是它前面离它最近的包含它的区间,为了方便我们加一个$(1,n,0)$,它可以作为树根而不影响答案
考虑树D,令$mx_i$表示区间$i$中$a$的最大值,$f_{i,j}$表示捐完子树$i$后区间$i$的最大值$\leq mx_i+j$的概率,若$1$为根,那么答案为$f_{1,0}\cdot mx_1+\sum\limits_{i=1}^q(f_{1,i}-f_{1,i-1})(mx_1+i)$
我们有转移$f_{i,j}=p_i\prod\limits_{u\in son(i)}f_{u,mx_i-mx_u+j-1}+(1-p_i)\prod\limits_{u\in son(i)}f_{u,mx_i-mx_u+j}$,捐/不捐有$1$的区别
然后就做完了...目测这场有点毒...?
#include<stdio.h> #include<algorithm> using namespace std; typedef double du; struct don{ int l,r,mx; du p; don(int a=0,int b=0,du c=0){l=a;r=b;p=c;} }d[5010]; bool operator<(don a,don b){return(a.l==b.l)?(a.r>b.r):(a.l<b.l);} int t[100010][17],lg[100010]; int query(int l,int r){ int k=lg[r-l+1]; return max(t[l][k],t[r-(1<<k)+1][k]); } int h[5010],nex[5010],to[5010],M; du f[5010][5010]; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } int m; void dfs(int x){ int i,j; du t1,t2; for(i=h[x];i;i=nex[i])dfs(to[i]); t2=1; for(i=h[x];i;i=nex[i])t2*=f[to[i]][d[x].mx-d[to[i]].mx]; f[x][0]=(1-d[x].p)*t2; for(j=1;j<=m;j++){ t1=t2=1; for(i=h[x];i;i=nex[i]){ t1*=f[to[i]][min(d[x].mx+j-d[to[i]].mx-1,m)]; t2*=f[to[i]][min(d[x].mx+j-d[to[i]].mx,m)]; } f[x][j]=d[x].p*t1+(1-d[x].p)*t2; } } int main(){ int n,i,j; du ans; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",t[i]); for(i=2;i<=n;i++)lg[i]=lg[i>>1]+1; for(j=1;j<17;j++){ for(i=1;i+(1<<j)-1<=n;i++)t[i][j]=max(t[i][j-1],t[i+(1<<(j-1))][j-1]); } for(i=1;i<=m;i++){ scanf("%d%d%lf",&d[i].l,&d[i].r,&d[i].p); d[i].mx=query(d[i].l,d[i].r); } m++; d[m]=don(1,n,0); d[m].mx=query(1,n); sort(d+1,d+m+1); for(i=2;i<=m;i++){ for(j=i-1;j>0;j--){ if(d[j].l<=d[i].l&&d[i].r<=d[j].r)break; } add(j,i); } dfs(1); ans=f[1][0]*d[1].mx; for(i=1;i<=m;i++)ans+=(f[1][i]-f[1][i-1])*(d[1].mx+i); printf("%.8lf",ans); }
标签:另一个 rod algo ace 就是 结构 printf [1] 表示
原文地址:https://www.cnblogs.com/jefflyy/p/9152997.html