考虑用费用流解决本题。
每个哨站看作一个点,并将其拆为两个点,建图方式为:
(S longrightarrow x_i) 容量为(1),费用为(0)
(x_i longrightarrow T) 容量为(1),费用为(w)
(x_i longrightarrow x^prime_j (i>j)) 容量为(1),费用为(|a_i-a_j|)
(x^prime_i longrightarrow T) 容量为(1),费用为(0)
这样就可以满足题目要求了,跑最小费用最大流即可求解,但发现边数为(n^2)级别,所以要考虑优化建图。
一个点在和拆出来的点连边时,只会向下标比其小的点连边,所以可以通过分治来实现优化建图。
对于区间([l,r]),分成两个区间([l,mid])和([mid+1,r]),每次从右区间向左区间连边。还需考虑费用的绝对值如何处理,可以把这一区间内所有的权值排序去重,然后连成一条链,链上边的费用为相邻两点的权值之差,然后把这条链作为连接右区间和左区间的虚点。
区间内的点向虚点连边时,只需找到其权值所对应到链上的位置,然后向对应位置连边即可,这样就通过累积权值之间的差值实现了费用的绝对值。
(code:)
#include<bits/stdc++.h>
#define maxn 800010
#define inf 2000000000
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,w,tot,cnt,s,t;
int p1[maxn],p2[maxn];
ll a[maxn],b[maxn],dis[maxn];
bool vis[maxn];
struct edge
{
int to,nxt,v;
ll c;
}e[maxn];
int head[maxn],edge_cnt=1;
void add(int from,int to,int val,ll cost)
{
e[++edge_cnt]=(edge){to,head[from],val,cost};
head[from]=edge_cnt;
e[++edge_cnt]=(edge){from,head[to],0,-cost};
head[to]=edge_cnt;
}
bool spfa()
{
for(int i=1;i<=tot;++i) vis[i]=0,dis[i]=inf;
queue<int> q;
q.push(s),dis[s]=0,vis[s]=true;
while(!q.empty())
{
int x=q.front();
q.pop(),vis[x]=false;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to,v=e[i].v;
ll c=e[i].c;
if(v&&dis[y]>dis[x]+c)
{
dis[y]=dis[x]+c;
if(!vis[y]) q.push(y),vis[y]=true;
}
}
}
return dis[t]!=inf;
}
int dfs(int x,int lim)
{
if(x==t) return lim;
vis[x]=true;
int res=lim,flow;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to,v=e[i].v;
ll c=e[i].c;
if(!v||dis[y]!=dis[x]+c||vis[y]) continue;
if(flow=dfs(y,min(res,v)))
{
res-=flow;
e[i].v-=flow;
e[i^1].v+=flow;
if(!res) break;
}
}
return lim-res;
}
ll dinic()
{
int flow;
ll sum=0;
while(spfa())
while(flow=dfs(s,inf))
sum+=flow*dis[t];
return sum;
}
void solve(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
solve(l,mid),solve(mid+1,r),cnt=0;
for(int i=l;i<=r;++i) b[++cnt]=a[i];
sort(b+1,b+cnt+1),cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<cnt;++i)
{
add(tot+i,tot+i+1,inf,b[i+1]-b[i]);
add(tot+i+1,tot+i,inf,b[i+1]-b[i]);
}
for(int i=l;i<=r;++i)
{
int pos=lower_bound(b+1,b+cnt+1,a[i])-b;
if(i>mid) add(p1[i],tot+pos,1,0);
else add(tot+pos,p2[i],1,0);
}
tot+=cnt;
}
int main()
{
read(n),read(w),s=++tot,t=++tot;
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<=n;++i)
{
p1[i]=++tot,p2[i]=++tot;
add(s,p1[i],1,0),add(p1[i],t,1,w),add(p2[i],t,1,0);
}
solve(1,n),printf("%lld",dinic());
return 0;
}