pinball
题目描述
A喜欢玩一个叫pinball的游戏。游戏规则如下:
Pinball的游戏界面由m+2行、n列组成。第一行在顶端。一个球会从第一行出发,开始垂直下落,A会得到一个积分当他击中一个球的时候。
小天才lyk觉得这太困难了,于是在界面中放入了一些漏斗,一共有m个漏斗分别放在第2~m+1行,第i个漏斗的作用是把经过第i+1行且列数在Ai~Bi之间的球将其移到第Ci列。
但是使用每个漏斗都是需要付钱的,第i个漏斗需要支付Di的价钱,A需要保留一些漏斗,使得球无论从第一行的哪一列开始放,都只可能到达第m+2行的唯一一列。同时,A希望花费最小的价钱。
输入
第一行两个数,m和n
接下来m行,第i+1行描述第i个漏斗的属性,Ai,Bi,Ci,Di(1<=Ai<=Ci<=Bi<=n,1<=Di<=1000000000)。
输出
若不存在一种方案能满足条件则输出-1,否则输出最小话费。
样例输入
5 6
2 4 3 5
1 2 2 8
3 6 5 2
4 6 4 7
2 4 3 10
3 5
2 4 3 10
1 3 1 20
2 5 4 30
样例输出
25
-1
提示
【样例解释1】
如图,只需使用第2、4、5个漏斗即可。
【数据范围】
对于20%的数据,m<=10,n<=1000
对于 40%的数据,m<=200
对于60%的数据,m<=1000
对于100%的数据,m<=100000,2<=n<=1000000000
“从所有列下落,最终都落在同一列”等价于“从第一列和最后一列下落最终在同一列”所以可以只算出1和n到各个列的最小花费,然后相加求最小
暴力
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long INF=(long long)1<<60;
struct node{
int x,y,z;
long long d;
}a[200050];
int p[600000];
long long dp1[600000],dp2[600000];
int main(){
int m,n;
scanf("%d%d",&m,&n);
if (m>1000){
cout<<"heSaBi"<<endl;
return 0;
}
int tot=0;
for (int i=1;i<=m;++i){
scanf("%d%d%d%lld",&a[i].x,&a[i].y,&a[i].z,&a[i].d);
p[tot++]=a[i].x;
p[tot++]=a[i].y;
p[tot++]=a[i].z;
}
p[tot++]=1;
p[tot++]=n;
sort(p,p+tot);
int t=unique(p,p+tot)-p;
for (int i=1;i<=m;++i){
a[i].x=lower_bound(p,p+t,a[i].x)-p;
a[i].y=lower_bound(p,p+t,a[i].y)-p;
a[i].z=lower_bound(p,p+t,a[i].z)-p;
}
for (int i=0;i<t;++i) dp1[i]=INF;
dp1[lower_bound(p,p+t,1)-p]=0;
for (int i=0;i<t;++i) dp2[i]=INF;
dp2[lower_bound(p,p+t,n)-p]=0;
long long ans=INF;
for (int i=1;i<=m;++i){
long long x1=INF;
for (int j=a[i].x;j<=a[i].y;++j)
x1=min(x1,dp1[j]);
long long x2=INF;
for (int j=a[i].x;j<=a[i].y;++j)
x2=min(x2,dp2[j]);
ans=min(ans,x1+x2+a[i].d);
dp1[a[i].z]=min(dp1[a[i].z],x1+a[i].d);
dp2[a[i].z]=min(dp2[a[i].z],x2+a[i].d);
}
if (ans>=INF) ans=-1;
printf("%lld\n",ans);
return 0;
}
线段树优化
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long INF=(long long)1<<60;
struct node{
int x,y,z;
long long d;
}a[200050];
int p[600000];
long long dp1[1300000],dp2[1300000];
long long find1(int l,int r,int z,int x,int y){
if (r<x||l>y) return INF;
if (x<=l&&r<=y) return dp1[z];
int mid=(l+r)/2;
return min(find1(l,mid,z+z,x,y),find1(mid+1,r,z+z+1,x,y));
}
long long find2(int l,int r,int z,int x,int y){
if (r<x||l>y) return INF;
if (x<=l&&r<=y) return dp2[z];
int mid=(l+r)/2;
return min(find2(l,mid,z+z,x,y),find2(mid+1,r,z+z+1,x,y));
}
void change1(int l,int r,int z,int x,long long h){
if (l>r) return;
if (l==r){
dp1[z]=min(dp1[z],h);
return;
}
int mid=(l+r)/2;
if (mid>=x)
change1(l,mid,z+z,x,h);
else
change1(mid+1,r,z+z+1,x,h);
dp1[z]=min(dp1[z+z],dp1[z+z+1]);
}
void change2(int l,int r,int z,int x,long long h){
if (l>r) return;
if (l==r){
dp2[z]=min(dp2[z],h);
return;
}
int mid=(l+r)/2;
if (mid>=x)
change2(l,mid,z+z,x,h);
else
change2(mid+1,r,z+z+1,x,h);
dp2[z]=min(dp2[z+z],dp2[z+z+1]);
}
int main(){
int m,n;
scanf("%d%d",&m,&n);
int tot=0;
for (int i=1;i<=m;++i){
scanf("%d%d%d%lld",&a[i].x,&a[i].y,&a[i].z,&a[i].d);
p[tot++]=a[i].x;
p[tot++]=a[i].y;
p[tot++]=a[i].z;
}
p[tot++]=1;
p[tot++]=n;
sort(p,p+tot);
int t=unique(p,p+tot)-p;
for (int i=1;i<=m;++i){
a[i].x=lower_bound(p,p+t,a[i].x)-p;
a[i].y=lower_bound(p,p+t,a[i].y)-p;
a[i].z=lower_bound(p,p+t,a[i].z)-p;
}
for (int i=1;i<=1200000;++i){
dp1[i]=INF;
dp2[i]=INF;
}
int hh=lower_bound(p,p+t,1)-p;
change1(0,t-1,1,hh,0);
hh=lower_bound(p,p+t,n)-p;
change2(0,t-1,1,hh,0);
long long ans=INF;
for (int i=1;i<=m;++i){
long long x1=find1(0,t-1,1,a[i].x,a[i].y);
long long x2=find2(0,t-1,1,a[i].x,a[i].y);
ans=min(ans,x1+x2+a[i].d);
change1(0,t-1,1,a[i].z,x1+a[i].d);
change2(0,t-1,1,a[i].z,x2+a[i].d);
}
if (ans>=INF) ans=-1;
printf("%lld\n",ans);
return 0;
}