P5896 [IOI2016]aliens
P5896 [IOI2016]aliens
一个
m\times m 的网格图上有n 个关键点,要求选至多k 个对角线为主对角线的正方形去覆盖它们。问这些正方形最少要覆盖多少个方格。
考虑 wqs 二分。设
考虑将左上角为
类似 P6047 丝之割,若
设
时间复杂度
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,k,cnt,g[N],q[N];
ll f[N],ans;
struct seg{int l,r;}a[N];
ll sq(int x){return 1ll*x*x;}
ll get(int i){
return f[i]+sq(a[i+1].l)-2*a[i+1].l-sq(max(0,a[i].r-a[i+1].l+1));
}
double slope(int i,int j){
return 1.0*(get(i)-get(j))/(a[i+1].l-a[j+1].l);
}
bool ok(ll c){
int l=0,r=0;
for(int i=1;i<=n;i++){
while(l<r&&slope(q[l],q[l+1])<2*a[i].r) l++;
f[i]=f[q[l]]+sq(a[i].r-a[q[l]+1].l+1)-sq(max(0,a[q[l]].r-a[q[l]+1].l+1))+c,g[i]=g[q[l]]+1;
while(l<r&&slope(q[r-1],q[r])>=slope(q[r],i)) r--;
q[++r]=i;
}
if(g[n]<=k) ans=f[n]-c*k;
return g[n]<=k;
}
signed main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].l,&a[i].r);
if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
}
sort(a+1,a+1+n,[](seg x,seg y){return x.l!=y.l?x.l<y.l:x.r>y.r;});
for(int i=1,r=-1;i<=n;i++)
if(a[i].r>r) r=a[i].r,a[++cnt]=a[i];
n=cnt,a[0].r=-1;
ll l=0,r=1ll*m*m;
while(l<=r){
ll mid=(l+r)/2;
if(ok(mid)) r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
return 0;
}