[PA2014]Muzeum
阿新 • • 發佈:2018-12-23
[PA2014]Muzeum
題目大意:
有\(n\)件展品和\(m\)個警衛,每件展品有一個座標\((x_i,y_i)\)和價值\(v_i\),每個警衛的座標為\((x_i,y_i)\)。每個警衛面朝\(y\)軸負方向,左右視角都為\(\theta\),警衛視線範圍內的展品不能偷。你可以收買一些警衛,使其放棄安保工作,收買第\(i\)個警衛的價格為\(v_i\)。你需要收買一些警衛並偷走一些展品,求盜取的總價值\(-\)收買的支出的最大值。
思路:
\(\tan(\theta)=\frac wh\),將所有點的\(x_i\)乘上\(h\),\(y_i\)乘上\(w\),再將所有點繞原點順時針旋轉\(45^\circ\)
將警衛當作“水源”,含\(v_i\)體積的水;展品當作“水桶”,容量為\(v_i\)。答案即為所有“水桶”容量之和\(-\)能被水桶吸收的水的體積。
從左到右列舉每一個警衛,set
中以縱座標為序維護警衛左邊的水桶的剩餘容量。從高到低列舉不高於警衛所在位置的水桶,並儘可能將水裝滿即可。
原始碼:
#include<set> #include<cstdio> #include<cctype> #include<algorithm> inline int getint() { register char ch; register bool neg=false; while(!isdigit(ch=getchar())) neg|=ch=='-'; register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return neg?-x:x; } typedef long long int64; const int N=2e5+1; struct Point { int64 x,y; int v; bool operator < (const Point &rhs) const { return x==rhs.x?y<rhs.y:x<rhs.x; } }; Point a[N],b[N]; std::set<std::pair<int64,int> > set; int main() { const int n=getint(),m=getint(); const int w=getint(),h=getint(); int64 ans=0; for(register int i=1;i<=n;i++) { const int64 x=1ll*getint()*h,y=1ll*getint()*w; a[i].x=x+y; a[i].y=y-x; a[i].v=getint(); ans+=a[i].v; } for(register int i=1;i<=m;i++) { const int64 x=1ll*getint()*h,y=1ll*getint()*w; b[i].x=x+y; b[i].y=y-x; b[i].v=getint(); } std::sort(&a[1],&a[n]+1); std::sort(&b[1],&b[m]+1); for(register int i=1,j=1;i<=m;i++) { for(;j<=n&&a[j].x<=b[i].x;j++) { set.insert(std::make_pair(a[j].y,a[j].v)); } while(b[i].v) { std::set<std::pair<int64,int> >::iterator it=set.lower_bound(std::make_pair(b[i].y+1,0)); if(it==set.begin()) break; std::pair<int64,int> p=*--it; set.erase(it); const int tmp=std::min(p.second,b[i].v); b[i].v-=tmp; p.second-=tmp; ans-=tmp; if(p.second) set.insert(p); } } printf("%lld\n",ans); return 0; }