51nod 1781 Pinball【DP】【线段树】

来源:互联网 发布:俄罗斯历史书籍知乎 编辑:程序博客网 时间:2024/06/12 19:24

Description

Pinball的游戏界面由m+2行、n列组成。第一行在顶端。一个球会从第一行的某一列出发,开始垂直下落,界面上有一些漏斗,一共有m个漏斗分别放在第2~m+1行,第i个漏斗的作用是把经过第i+1行且列数在Ai~Bi之间的球,将其移到下一行的第Ci列。 使用第i个漏斗需要支付Di的价钱,你需要保留一些漏斗使得球无论从第一行的哪一列开始放,都只可能到达第m+2行的唯一 一列,求花费的最少代价。

(样例的图)

img

(我们保留2,4,5即可,代价为5+3+12=20)

题解

竟然没有想到。。。

只要最左边的点和最右边的点都被包括了就是一种解,所以,可以定义L[i]表示第i个漏斗作为最后一个,最左边的位置落到这个漏斗的最小代价,R[i]表示第i个漏斗作为最后一个,最右边的位置落到这个漏斗的最小代价,那么最后答案就是min{L[i]+R[i]w[i]},只要从上往下DP,可以发现,状态转移的过程其实就是区间求最小值,所以只要对横坐标离散一下,然后用线段树维护就可以了。最后还要注意,离散出来的点最多可能有3n个,相应的,线段树也要开到这个值的4倍。

代码

#include<cstdio>#include<cstring>#include<algorithm>#define maxn 100006#define LL long longusing namespace std;inline char nc(){    static char buf[100000],*i=buf,*j=buf;    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}inline int _read(){    char ch=nc();int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}struct fy{    int l,r,c;    LL L,R,w;}a[maxn];int n,m,b[maxn*3],id[maxn*3];LL ans;struct data{    int l,r;    LL x;}tree[maxn*12];void build(int p,int l,int r){    tree[p].l=l;tree[p].r=r;tree[p].x=1e18;    if(l>=r)return;    int mid=(l+r)>>1;    build(p<<1,l,mid);build(p<<1|1,mid+1,r);}void update(int p,int x,LL k){    if(tree[p].r<x||tree[p].l>x)return;    if(tree[p].l==tree[p].r){tree[p].x=min(tree[p].x,k);return;}    update(p<<1,x,k);update(p<<1|1,x,k);    tree[p].x=min(tree[p<<1].x,tree[p<<1|1].x);}LL query(int p,int l,int r){    if(tree[p].r<l||tree[p].l>r)return 1e18;    if(l<=tree[p].l&&r>=tree[p].r)return tree[p].x;    return min(query(p<<1,l,r),query(p<<1|1,l,r));}int find(int x){    int l=1,r=b[0];    while(l<=r){        int mid=(l+r)>>1;        if(b[mid]==x)return id[mid];        if(b[mid]<x)l=mid+1;               else r=mid-1;    }}int main(){    freopen("pinball.in","r",stdin);    freopen("pinball.out","w",stdout);    m=_read();n=_read();b[1]=1;b[2]=n;b[0]=2;    if(n==1)return printf("0\n"),0;    for(int i=1;i<=m;i++)     a[i].l=_read(),a[i].r=_read(),a[i].c=_read(),a[i].w=_read(),     b[++b[0]]=a[i].l,b[++b[0]]=a[i].r,b[++b[0]]=a[i].c;    sort(b+1,b+1+b[0]);    for(int i=1;i<=b[0];i++) if(b[i]!=b[i-1])id[i]=id[i-1]+1;else id[i]=id[i-1];    for(int i=1;i<=m;i++)a[i].l=find(a[i].l),a[i].r=find(a[i].r),a[i].c=find(a[i].c);    build(1,1,id[b[0]]);    update(1,1,0);    for(int i=1;i<=m;i++){        a[i].L=query(1,a[i].l,a[i].r)+a[i].w;        update(1,a[i].c,a[i].L);    }    build(1,1,id[b[0]]);    update(1,id[b[0]],0);    for(int i=1;i<=m;i++){        a[i].R=query(1,a[i].l,a[i].r)+a[i].w;        update(1,a[i].c,a[i].R);    }    ans=1e18;    for(int i=1;i<=m;i++)ans=min(ans,a[i].L+a[i].R-a[i].w);    if(ans>=1e18)printf("-1\n");else printf("%lld\n",ans);    return 0;}
原创粉丝点击