CF559E Gerald and Path


題面:https://codeforces.com/contest/559/problem/E https://www.luogu.com.cn/problem/CF559E
題意:
\(n\)條線段。
每條線段給定其中一端的位置及長度。
求所有線段覆蓋的最大長度。
n \(\leq\) 100。
題解:
O(\(n^4\)):自己去CF上看
首先考慮如果已經確定每條線段選左邊還是右邊,我們
計算總長的方法是把所有線段按\(l\)\(r\)排序,然后維護一個
\(maxl\)或者\(maxr\),表示當前覆蓋到的最左或最右在哪。
此題的難處在於如何避免重復計算貢獻。
首先對坐標離散化,按\(a[i]\)排序。現在考慮模擬上面的計算過程。
\(f[i][j]\)表示考慮到第\(i\)個點,已經覆蓋到右端點為\(j\)的最大值。
顯然,有\(f[i][j]=max(f[i][j],f[i][j-1])\)
設當前i的信息為X,Y,P。
考慮每次新加一條線段的兩種轉移:
1.向右:這個可以直接由上一個轉移,\(f[i][j]=f[i-1][P]+dist(P,j)\)
2.向左:\(f[i][?]=f[i-1][?]+dist(X,?)\)
發現我們並不知道左邊的線段是否與當前線段沖突。
所以需要枚舉一個\(k\),強行讓[k,i-1]的所有線段向右,
這樣就可以確定一個最右端點,設其為\(R\)。由此我們得出:\(f[i][R]=f[k-1][X]+dist(X,R)\)
為什么可以指定這段區間的所有線段向右呢?這樣不會使答案變差嗎?
考慮如果中間有線段\(k1\)向左,那么它的貢獻早在當前的\(i\)向右時算過了。
這樣做復雜度是O(\(n^3\))的。考慮優化這個DP。
發現如果我們倒序枚舉\(k\),那么\(R\)一定是單增的。
\(g[R]\)代表對於當前的\(i\)\(f[k-1][X]+dist(X,R)\)的最大值。
這樣,我們可以先處理出\(g\),然后得到\(f\)
注意實現過程中要多次用到前綴、后綴最大值的思想。
時間復雜度:O(\(n^2\))
代碼:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
const int INF=1e9+7;
struct P{
	int x,y,a;
	friend bool operator < (P a,P b){return a.a<b.a;}
}p[110];
vector<int>v;
int n,m,f[110][330],g[330],L,R,P,X,Y;
I get(int &x){x=lower_bound(v.begin(),v.end(),x)-v.begin();}
int main(){
	read(n);v.emplace_back(-INF);
	F(i,1,n){
		read(p[i].a);read(m);p[i].x=p[i].a-m;p[i].y=p[i].a+m;
		v.emplace_back(p[i].a);v.emplace_back(p[i].x);v.emplace_back(p[i].y);
	}
	sort(p+1,p+1+n);
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());m=v.size()-1;
	F(i,1,n)get(p[i].a),get(p[i].x),get(p[i].y);
	F(i,1,n){
		F(j,1,m)f[i][j]=f[i-1][j];
		X=p[i].x;Y=p[i].y;P=p[i].a;
		R=P;C(g,0);
		g[R]=f[i-1][X]+v[R]-v[X];
		FOR(j,i-1,1){
			R=max(R,p[j].y);
			g[R]=max(g[R],f[j-1][X]+v[R]-v[X]);
		}
		FOR(j,m,X)f[i][j]=max(f[i][j],g[j]),g[j-1]=max(g[j-1],g[j]-v[j]+v[j-1]);
		F(j,P,Y)f[i][j]=max(f[i][j],f[i-1][P]+v[j]-v[P]);
		F(j,1,m)f[i][j]=max(f[i][j],f[i][j-1]);
	}
	cout<<f[n][m];
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM