Codeforces Round #107 (Div. 1) C Smart Cheater
题目链接:Smart Cheater
题意:一辆公交车共有 n 个车站,有 m 位乘客,已知所有车站的位置 x[i] 和每位乘客所乘车区间,两个车站间的车票价格为 x[i+1]-x[i]。对于每位乘客,售票员可以选择至多一段连续区间不售这段区间的票,并和乘客平分这个钱。但是每一相邻区间都有 p[i] 的概率出现监督员,如果监督员发现有乘客没有这段区间的车票,售票员就会被罚款 c。问售票员收到的钱的最大期望。
题解:对于每一个乘客,每一个相邻区间是一样的,可以分别计算出每个区间一位乘客的期望价格为:(x[i+1]-x[i])/2-c*p[i]。现在问题转化为了多次查询某个区间内的最大连续子序列和,用线段树处理。线段树中存储四个信息:区间全部的和 sum_all、以左端点为连续区间起点的最大连续字段和 sum_l、以右端点为连续区间终点的最大连续字段和 sum_r、这个区间内的最大连续字段和 sum_ans。其区间内的最大连续字段和,要么是左子树的 sum_l,要么是右子树的 sum_r,或者是左子树的 sum_r + 右子树的 sum_l。
#include <bits/stdc++.h> #define mid ((l+r)/2) #define lson (id<<1) #define rson ((id<<1)+1) using namespace std; int n,m,fine; int x[150005],p[1500005],on[300005],off[300005]; double a[150005]; struct node{ int on,off; } pass[300005]; struct Node{ int l,r; double sum_l,sum_r,sum_all,sum_ans; } tre[150005*4]; void build(int id,int l,int r){ tre[id].l=l; tre[id].r=r; if(l==r){ tre[id].sum_l=a[l]; tre[id].sum_r=a[l]; tre[id].sum_all=a[l]; tre[id].sum_ans=a[l]; return; } build(lson,l,mid); build(rson,mid+1,r); tre[id].sum_l=max(tre[lson].sum_l,tre[lson].sum_all+tre[rson].sum_l); tre[id].sum_r=max(tre[rson].sum_r,tre[rson].sum_all+tre[lson].sum_r); tre[id].sum_ans=max(max(tre[lson].sum_ans,tre[rson].sum_ans),tre[lson].sum_r+tre[rson].sum_l); tre[id].sum_all=tre[lson].sum_all+tre[rson].sum_all; } Node query(int id,int ql,int qr){ if(ql==tre[id].l&&tre[id].r==qr){ return tre[id]; } int l=tre[id].l,r=tre[id].r; if(qr<=mid) return query(lson,ql,qr); if(ql>mid) return query(rson,ql,qr); Node New_l=query(lson,ql,mid); Node New_r=query(rson,mid+1,qr); Node res; res.sum_l=max(New_l.sum_l,New_l.sum_all+New_r.sum_l); res.sum_r=max(New_r.sum_r,New_r.sum_all+New_l.sum_r); res.sum_all=New_l.sum_all+New_r.sum_all; res.sum_ans=max(max(New_l.sum_ans,New_r.sum_ans),New_l.sum_r+New_r.sum_l); return res; } int main(){ scanf("%d%d%d",&n,&m,&fine); for(int i=1;i<=n;i++) scanf("%d",&x[i]); for(int i=1;i<n;i++) scanf("%d",&p[i]); for(int i=1;i<=m;i++) scanf("%d%d",&pass[i].on,&pass[i].off); double ans=0; for(int i=1;i<n;i++){ a[i+1]=1.0*(x[i+1]-x[i])/2.0-1.0*p[i]/100.0*fine; } build(1,1,n); for(int i=1;i<=m;i++){ double res=query(1,pass[i].on+1,pass[i].off).sum_ans; ans+=max(res,0.0); } printf("%.9f\n",ans); return 0; }