P5896 [IOI 2016] aliens
这是我第一道不看题解做出正解的黑题!实现细节与所有题解均不同!
:::info[喜提洛谷当前最优解] 精细实现一下抢到了最优解 https://www.luogu.com.cn/record/228655964。 :::
:::warning[Hint]{open}
考虑一个正方形可以覆盖一个兴趣点
注意到我们所选取的
自此,转化为区间覆盖问题。
同时结合题目中对拍摄次数的限制,不难想到是 wqs 二分套斜率优化 DP。 :::
我们令
则状态转移方程为:
再次利用所选区间互不包含的性质,我们将
其中
时间复杂度
:::warning[维护下凸壳时的易错点]{open}
注意到此题中横坐标
所以一定要注意决策点重合的情况。 :::
:::success[[IOI 2016] aliens - P5896.cpp]{open}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5,maxm=1e6+5;
int pos[maxm],vis[maxm],sta[maxn],cnt[maxn],n,m,k,top;
ll py[maxn],pre[maxn],dp[maxn];
inline ll squ(ll val){return val*val;}
inline bool check(int u,int v,int w){
return (py[v]-py[u])*(pos[w]-pos[v])>=(py[w]-py[v])*(pos[v]-pos[u]);
}
inline void solve(ll mid){
int pl=1,pr=1;
py[0]=pre[0];
for(int i=1;i<=top;++i){
while(pl<pr and (py[sta[pl+1]]-py[sta[pl]])
<2ll*vis[i]*(pos[sta[pl+1]]-pos[sta[pl]])) ++pl;
dp[i]=py[sta[pl]]-2ll*vis[i]*pos[sta[pl]]+squ(vis[i]+1)+mid;
cnt[i]=cnt[sta[pl]]+1;
py[i]=dp[i]+pre[i];
while(pl<pr and check(sta[pr-1],sta[pr],i)) --pr;
sta[++pr]=i;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>k;
int u,v;
for(int i=0;i<=m;++i) pos[i]=1e9;
for(int i=1;i<=n;++i){
cin>>u>>v;
++u,++v;
if(u>v) swap(u,v);
pos[v-1]=min(pos[v-1],u);
vis[v]=1;
}
for(int i=m-1;i>=0;--i) pos[i]=min(pos[i],pos[i+1]);
for(int i=1;i<=m;i++) if(vis[i]) vis[++top]=i;
for(int i=0;i<=top;i++){
pos[i]=pos[vis[i]];
pre[i]=1ll*pos[i]*pos[i]-2*pos[i]-squ(max(0,vis[i]-pos[i]+1));
}
ll l=0,r=1ll*m*m,mid,res=0;
while(l<=r){
mid=(l+r)>>1;
solve(mid);
if(cnt[top]<=k) res=mid,r=mid-1;
else l=mid+1;
}
solve(res);
cout<<(dp[top]-k*res)<<"\n";
return 0;
}
:::