[CF1408D] Searchlights

Description

(n) 个坐标为 ((a_i,b_i)) 的人,有 (m) 个坐标为 ((c_i,d_i)) 的灯。

每次操作,要么让所有 (a_i+1),要么让所有 (b_i+1)

如果一个人的横纵坐标都不大于灯的横纵坐标,那么这个人是安全的。

求最小移动多少次使得所有人都是安全的。

Solution

设人的编号为 (i),灯的编号为 (j),则对于任意 (i,j),以下两式必须要有至少一个成立:(x+a[i] > c[i],y+b[i] > d[i])

假设将一个人移动到 ((x,y)),设 (x le c[j]-a[i]),那么 (y ge d[j]-b[i]+1)

于是我们在 (x=c[j]-a[i]) 的位置上打一个 (d[j]-b[i]+1)(max) 标记,最后对所有标记做一次后缀 (max) 即可。

#include <bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 5005;
const int M = 1000005;

int n,m,a[N],b[N],c[N],d[N],f[M];

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
    for(int i=1;i<=m;i++) cin>>c[i]>>d[i];

    for(int i=1;i<=n;i++) 
    {
        for(int j=1;j<=m;j++)
        {
            if(c[j]-a[i]>=0)
            {
                f[c[j]-a[i]]=max(f[c[j]-a[i]],d[j]-b[i]+1);
            }
        }
    }

    for(int i=M-1;i>=0;i--) f[i]=max(f[i],f[i+1]);

    int ans=1e18;

    for(int i=0;i<M;i++) ans=min(ans,i+f[i]);

    cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/14099863.html