码迷,mamicode.com
首页 > 其他好文 > 详细

CF559E Gerald and Path

时间:2019-12-28 13:18:38      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:register   namespace   区间   c++   lower   space   friend   ORC   cto   

题面: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;
}

CF559E Gerald and Path

标签:register   namespace   区间   c++   lower   space   friend   ORC   cto   

原文地址:https://www.cnblogs.com/Purple-wzy/p/12111245.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!