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;
}

 

posted on 2019-01-15 09:55  Psong  阅读(116)  评论(0编辑  收藏  举报

导航