2019牛客暑期多校训练营(第九场)J Symmetrical Painting (思维)

传送门
大体思路就是:枚举所有可能的水平对称线,计算面积更新答案。

所有可能的水平对称线:\(L_i,R_i,{L_i+R_i\over 2}\)

计算面积:将所有可能的水平对称线从小到大排序,然后依次计算。

假设算出了第\(i-1\)条对称线的答案,然后更新第\(i\) 条的,两个的高度差为\(h\)

对于块1,贡献多了\(2h\),对块2并没有贡献。

当更新第\(i+1\)条时,高度差为\(h_2\),对块1的贡献为\(2h_2\),对块2的贡献为\(2h_2\)

当更新第\(i+2\)条时,高度差为\(h_3\),对块1的贡献为\(-2h_3\),对块2的贡献为\(2*h_3\)

\(\cdots\)

可以发现,如果枚举的对称线过了某个块的底线,那么这个贡献就是高度差的2倍,如果过了该块的对称线,贡献就是负的高度差的2倍,如果过了顶线,贡献为0。

所以要时刻记录以下两种块的数量差:

\[已过底线但未过对称线 - 已过对称线但未过顶线 \]

体现在程序中可以通过底线时,个数++,通过对称线时,个数-2,通过顶线++

另外可以先把高度都乘2,在计算过程中就不必再乘2了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300010;
typedef pair<int,int> pii;
vector<pii> v;
int n;
int main(){
    scanf("%d",&n);Q
    for(int i=1;i<=n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        v.push_back({x+x,1});
        v.push_back({x+y,-2});
        v.push_back({y+y,1});
    }
    sort(v.begin(),v.end());
    ll res = 0,sum = 0,last = 0,sz = 0;
    for(auto x : v){
        sum += sz * (x.first - last);
        res = max(res,sum);
        sz += x.second;
        last = x.first;
    }
    cout<<res<<endl;
    return 0;
}
posted @ 2019-08-20 16:19  kpole  阅读(212)  评论(0编辑  收藏  举报