CF1662I Ice Cream Shop 题解

jiangtaizhe001

2022-04-26 19:48:49

题解

可能更好的阅读体验

题目大意

在沙滩上有 n 个小屋,可以看做小屋在一条数轴上,第 i 个小屋的位置为 (i-1)\times100,里面有 p_i 个人。这条数轴上还有 m 个小屋,每个买冰淇淋的商店,第 i 个商店的位置为 x_i
现在你可以再数轴上任意一个位置(不需要为整数!)开一个冰淇淋商店,如果一个小屋到你开的冰淇淋店的距离比原有所以的冰淇淋点更加近,那么这个小屋里面所有的人都会到你开的冰淇淋店买冰淇淋。
注意可能存在冰淇淋店和小屋在同一位置,你开的冰淇淋店也可以和小屋在同一位置。
现在求到你开的冰淇淋店买冰淇淋的人的最大人数。

### 题目解析 我们可以先求出第 $i$ 个小屋的人到你开的冰淇淋店来买冰淇淋,需要满足冰淇淋店的位置(一个开区间 $(l_i,r_i)$),不难发现,如果设 $f_i$ 为距离第 $i$ 个小屋最近的冰淇淋店的位置,那么这个序列不降,所以只需要将冰淇淋店的坐标从小到大排序然后扫一次就好了。 这样就相当于每个区间存在一个价值,然后选择若干区间使得这些区间的交集不为空,然后求最大的价值。 然后只需要按照左端点排序,开一个 `set` 维护包含第 $i$ 个区间,并且和这个区间交集不为空的区间即可。 复杂度 $O\left(m\log m+n\log n\right)

核心代码:

int n,m,dis[maxn],tmp; ll sum,ans;
struct JTZ{ int l,r,p; bool operator < (const JTZ x) const { return this->r<x.r; } }a[maxn];
int cmp(JTZ x,JTZ y){ return x.l<y.l; } multiset<JTZ> s;
#define dis(i) (((i)-1)*100)
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    n=read(); m=read(); int i,j; for(i=1;i<=n;i++) a[i].p=read();
    for(i=1;i<=m;i++) dis[i]=read(); sort(dis+1,dis+m+1);
    j=1; for(i=1;i<=n;i++){
        while(j<m&&mabs(dis[j]-dis(i))>mabs(dis[j+1]-dis(i))) j++;
        tmp=mabs(dis[j]-dis(i)); a[i].l=dis(i)-tmp,a[i].r=dis(i)+tmp;
    } sort(a+1,a+n+1,cmp); s.clear(); set<JTZ>::iterator it;
    for(i=1;i<=n;i++) if(a[i].l<a[i].r){
        if(!s.empty()){
            it=s.begin();
            while((*it).r<=a[i].l){
                sum-=(*it).p; s.erase(it);
                if(!s.empty()) it=s.cbegin(); else break;
            }
        } sum+=a[i].p; s.insert(a[i]); ans=mmax(ans,sum);
    } print(ans); return 0;
}