51nod 1781 Pinball【DP】【線段樹】

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 long
using 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;
}
發佈了143 篇原創文章 · 獲贊 18 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章