51nod-3986-免費的餡餅

wscqwq發表於2024-07-28

https://class.51nod.com/Html/Textbook/Problem.html#problemId=3986&textbookChapterId=725

https://class.51nod.com/Html/Textbook/ChapterIndex.html#textbookId=126&chapterId=338

我們將餡餅表示為 \((p_i,t_i)\),即一個平面直角座標系上的點。

我們把餡餅看成靜止,人每次往上移動一格。

記當前點為 \((x_0,y_0)\),考慮能轉移到當前點的餡餅滿足的條件。

向上走的路程為 \(y_0-y\),左右為 \(x_0-x\)

一直往右:\(2(y_0-y)=x_0-x\)

一直往左:\(-2(y_0-y)=x_0-x\)。(此時兩邊都是負值)

由於每次只能最多走2格,所以 \(2(y_0-y)\ge x_0-x\),得 \(x-2y\ge x_0-2y_0\),變為 \(2y-x\le 2y_0-x_0\)

同理,\(-2(y_0-y)\le x_0-x\)。(即左邊的絕對值更大),得 \(x+2y\le x_0+2y_0\)

單獨滿足一個條件不滿足 \(y<y_0\),但是同時滿足就同時滿足這一條件,如圖:

image-20240728095812541

動態:https://www.geogebra.org/m/zv9vwhzk

即紫色區域。

至此,令 \(x'=2y-x,y'=x+2y\),此時變成了一個二維偏序問題,只要滿足 \(x'\le x_0',y'\le y_0'\) 的就可以轉移。

透過排序去掉一維,另一維樹狀陣列維護之。

當然要離散化樹狀陣列那一維。

\(O(n\log n)\)

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int w,n,ls[N],f[N];
struct bing{
	int x,y,v,lv,rv;
	void init(){
		cin>>y>>x>>v;
		lv=y*2-x;
		rv=x+y*2;
	}
	bool operator<(const bing&B)const{
		// return rv<B.rv;
		return rv^B.rv?rv<B.rv:lv<B.lv;
	}
}b[N];
int c[N];
void add(int x,int v){
	for(;x<=n;x+=x&-x)c[x]=max(c[x],v);
}
int sum(int x){
	int res=0;
	for(;x;x-=x&-x)res=max(res,c[x]);
	return res;
}
int main(){
	#ifdef LOCAL
	freopen("1.txt","r",stdin);
	#endif
	#ifndef LOCAL
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	#endif
	cin>>w>>n;
	for(int i=1;i<=n;++i)b[i].init(),ls[i]=b[i].lv;
	sort(b+1,b+1+n);
	// for(int i=1;i<=n;++i)
		// cout<<b[i].rv<<' '<<b[i].lv<<' '<<b[i].v<<'\n';
	sort(ls+1,ls+1+n);
	int m=unique(ls+1,ls+1+n)-ls-1;
	for(int i=1;i<=n;++i)
		b[i].lv=lower_bound(ls+1,ls+1+m,b[i].lv)-ls;
	int ans=0;
	for(int i=1;i<=n;++i){
		f[i]=sum(b[i].lv)+b[i].v;
		ans=max(ans,f[i]);
		add(b[i].lv,f[i]);
	}
	cout<<ans;
	return 0;
}

相關文章