题解:P17319 [ICPC 2018 Nanjing R] Tournament
简化 Larsch 有些烂大街了,这道题都被教练投给学弟做了。
邮局,aliens。
Solution
定义一段连续的房子
其中
于是有差分:
由于题目保证了
选定若干个地址,求距离和最小,可以转换:将序列划分成
我们断言,
恒成立即可。
由于
移项即证
| 再者,使用决策单调性更容易证明,在此不再展开。 |
|---|
这就变成十分经典的 trick 了,外层套一个 WQS 二分,内层使用简化 Larsch。具体的,对于每新加入一个划分,就获得一个惩罚
简化 Larsch 请参考 Noshi91 的博客:簡易版 LARSCH Algorithm。
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
const int N=2e6+10,mod=998244353;
typedef pair<int,int> pii;
typedef long long ll;
/*
*/
int C,T=1;
int m,n,k,a[N],sum[N],v;
int w(int l,int r){
int p=(l+r)>>1;
return sum[r]-2*sum[p]+sum[l-1]-a[p]*(r-2*p+l-1);
}
int cnt[N],p[N],dp[N],X;
inline void cmin(int u,int v){
ll x=dp[v]+w(v+1,u)+X;
if(x<dp[u]) dp[u]=x,p[u]=v,cnt[u]=cnt[v]+1;
if(x==dp[u]&&cnt[v]+1<cnt[u]) cnt[u]=cnt[v]+1,p[u]=v;
}
void Larsch(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
for(int i=p[l-1];i<=p[r];i++) cmin(mid,i);
Larsch(l,mid);
for(int i=l;i<=mid;i++) cmin(r,i);
Larsch(mid+1,r);
}
bool chk(){
for(int i=1;i<=n;i++) cnt[i]=p[i]=0,dp[i]=1e15;
cmin(n,0); Larsch(1,n);
return cnt[n]<=k;
}
void Lain(){
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i],sum[i]=sum[i-1]+a[i];
int B=w(1,n),l=0,r=B,as;
while(l<r-1) X=(l+r)>>1,chk()?r=X:l=X;
X=l,chk(),as=dp[n]-l*k;
X=r,chk(),as=max(as,dp[n]-r*k);
cout<<as<<"\n";
return;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
// cin>>C>>T;
while(T--) Lain();
return 0;
}