• 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;
    }
    
  • 相关阅读:
    大话设计模式笔记(十三)の状态模式
    大话设计模式笔记(十二)の抽象工厂模式
    大话设计模式笔记(十一)の观察者模式
    大话设计模式笔记(十)の建造者模式
    大话设计模式笔记(九)の外观模式
    大话设计模式笔记(八)の模板方法模式
    大话设计模式笔记(七)の原型模式
    Vue(十二):自定义指令和函数渲染
    Vue(十一):组件边界
    Vue(十):混入、插件和过滤器
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/12111245.html
Copyright © 2020-2023  润新知