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

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

所有可能的水平对称线:(L_i,R_i,{L_i+R_iover 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;
}
原文地址:https://www.cnblogs.com/1625--H/p/11383636.html