首页 > 代码库 > 51Nod 欢乐手速场1 A Pinball[DP 线段树]
51Nod 欢乐手速场1 A Pinball[DP 线段树]
Pinball
xfause (命题人)
基准时间限制:1 秒 空间限制:262144 KB 分值: 20
Pinball的游戏界面由m+2行、n列组成。第一行在顶端。一个球会从第一行的某一列出发,开始垂直下落,界面上有一些漏斗,一共有m个漏斗分别放在第2~m+1行,第i个漏斗的作用是把经过第i+1行且列数在Ai~Bi之间的球,将其移到下一行的第Ci列。 使用第i个漏斗需要支付Di的价钱,你需要保留一些漏斗使得球无论从第一行的哪一列开始放,都只可能到达第m+2行的唯一 一列,求花费的最少代价。
(样例的图)
(我们保留2,4,5即可,代价为5+3+12=20)
Input
第一行两个数,m和n。m<=100000,2<=n<=1000000000接下来m行,第i+1行描述第i个漏斗的属性,Ai,Bi,Ci,Di (1<=Ai<=Ci<=Bi<=n, 1<=Di<=1000000000)。
Output
若不存在一种方案能满足条件则输出-1,否则输出最小花费
Input示例
5 63 5 4 81 4 3 54 6 5 75 6 5 33 5 4 12
Output示例
20
最后一定经过同一个漏斗
枚举最后经过哪个漏斗,然后求出第1列和第n列到达这个漏斗的最小花费就好了
考虑DP L[i]和R[i]
L[i]表示从1下落使用漏斗i到达C[i]的最小话费 L[i]=min{L[j] : A[i]<=C[j]<=B[i]}+D[i]}
这种带修改的RMQ问题用个线段树就好了
当然要离散化列啦
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;#define lson x<<1,l,mid#define rson x<<1|1,mid+1,r#define lc x<<1#define rc x<<1|1typedef long long ll;const int N=1e5+5,M=3e5+5;const ll INF=1e18;inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f;}int n,m,a[N],b[N],c[N],d[N];int mp[M];void iniMP(){ sort(mp+1,mp+1+mp[0]); int p=0;mp[++p]=mp[1]; for(int i=2;i<=mp[0];i++) if(mp[i]!=mp[i-1]) mp[++p]=mp[i]; mp[0]=p;}int Bin(int v){ int l=1,r=mp[0]; while(l<=r){ int mid=(l+r)>>1; if(mp[mid]==v) return mid; else if(v<mp[mid]) r=mid-1; else l=mid+1; } return 0;}ll t[M<<2];void build(int x,int l,int r){ if(l==r) t[x]=INF; else{ int mid=(l+r)>>1; build(lson); build(rson); t[x]=min(t[lc],t[rc]); }}void segCha(int x,int l,int r,int p,ll v){ if(l==r) t[x]=min(t[x],v);//!!! else{ int mid=(l+r)>>1; if(p<=mid) segCha(lson,p,v); else segCha(rson,p,v); t[x]=min(t[lc],t[rc]); }}ll segMin(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return t[x]; else{ ll re=INF; int mid=(l+r)>>1; if(ql<=mid) re=min(re,segMin(lson,ql,qr)); if(mid<qr) re=min(re,segMin(rson,ql,qr)); return re; }}ll L[N],R[N];void solve(){ build(1,1,mp[0]); segCha(1,1,mp[0],1,0);// printf("check %d %d\n",segMin(1,1,mp[0],2,5),segMin(1,1,mp[0],1,5)); for(int i=1;i<=n;i++){ L[i]=segMin(1,1,mp[0],a[i],b[i])+d[i]; segCha(1,1,mp[0],c[i],L[i]); //printf("L %d %d\n",i,L[i]); } build(1,1,mp[0]); segCha(1,1,mp[0],mp[0],0); for(int i=1;i<=n;i++){ R[i]=segMin(1,1,mp[0],a[i],b[i])+d[i]; segCha(1,1,mp[0],c[i],R[i]); //printf("R %d %d\n",i,R[i]); } ll ans=INF; for(int i=1;i<=n;i++) ans=min(ans,L[i]+R[i]-d[i]); if(ans<INF) printf("%lld",ans); else puts("-1");}int main(){// freopen("in.txt","r",stdin); n=read();m=read(); mp[++mp[0]]=1;mp[++mp[0]]=m; for(int i=1;i<=n;i++){ mp[++mp[0]]=a[i]=read(); mp[++mp[0]]=b[i]=read(); mp[++mp[0]]=c[i]=read(); d[i]=read(); } iniMP(); //for(int i=1;i<=mp[0];i++) printf("mp %d %d\n",i,mp[i]); for(int i=1;i<=n;i++) a[i]=Bin(a[i]),b[i]=Bin(b[i]),c[i]=Bin(c[i]); solve();}
51Nod 欢乐手速场1 A Pinball[DP 线段树]
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。