题意
个顺时针排列的牛棚,可以开
个口让牛顺时针进入,已知每个牛棚需要多少只牛,问所有牛在牛棚内行走的距离总和最小值。
思路
序列倍长,断环成链,区间转移,线性动归,这种套路实在见得多了,不难打出一个 的 如下:
FOR(r,0,n-1)
{
FOR(i,1,n)cnt[i]=cnt[i-1]+a[r+i],sum[i]=sum[i-1]+a[r+i]*i;
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
FOR(i,1,K)
FOR(j,1,n)
FOR(k,0,j-1)
dp[i][j]=min(dp[i][j],dp[i-1][k]+(sum[j]-sum[k])-(k+1)*(cnt[j]-cnt[k]));
ans=min(ans,dp[K][n]);
}
现在优化掉其中一维即可,显然是转移的那一维,列出转移式:
把和
有关或常数提出来,将只和
有关、与
有关的分别并列得到:
令
原式又变成
维护一个
的下凸包,即保证斜率一定时,
轴上截距最小,而斜率的
又是单调递增的,那斜率优化就显然了。
总结一下斜率是如何优化
的。
回到我们的单调队列优化
,
,
相同。
其中
是仅与
相关的函数,
是只与
相关的函数,维护一个关于
的单调队列即可。
而当出现了
这种
函数内的式子与转出者
和转入者
均有关的式子时,普通的单调队列已经无能为力。
我们联想到一次函数的解析式
,把
洒在坐标轴上,不难发现
就是点斜式方程
的在
轴上的截距。对于上面这样一条转移式,其实求的就是若干个坐标轴上的点,拿一条斜率为
的直线去截某一个点,能得到最小的截加上常数
,当然
是递增的(有时通过排序保证单调性),那只用维护一个下凸包,每次转移前删去非最优的左端点再转移,加入点要保证形成下凸包。
也是同理,只不过下凸包换成了上凸包,斜率递增改成斜率递减即可。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=503;
bool cmp(LL x,LL y){return x<y;}
template<bool cmp(LL,LL)>struct mulnoque
{
int L,R;LL Qx[N],Qy[N];
mulnoque(){clear();}
void clear(){L=1,R=0;}
void push(LL x,LL y){Qx[++R]=x,Qy[R]=y;}
void pop(LL k){while(L<R&&!cmp(k*(Qx[L+1]-Qx[L]),Qy[L+1]-Qy[L]))L++;}
void del(LL x,LL y){while(L<R&&!cmp((Qy[R]-Qy[R-1])*(x-Qx[R]),(y-Qy[R])*(Qx[R]-Qx[R-1])))R--;}
LL X(){return Qx[L];}LL Y(){return Qy[L];}
};
mulnoque<cmp>Q;
LL dp[13][N],cnt[N],sum[N];
int _a[2*N],*a=_a;
int n,K;
LL getY(int x,int y){return dp[x-1][y]-sum[y]+(y+1)*cnt[y];}
LL getK(int x){return cnt[x];}
LL getX(int x){return x+1;}
LL getC(int x){return sum[x];}
int main()
{
scanf("%d%d",&n,&K);
FOR(i,1,n)scanf("%d",&_a[i]);
FOR(i,n+1,2*n)_a[i]=_a[i-n];
LL ans=1e15;
FOR(r,0,n-1)
{
FOR(i,1,n)cnt[i]=cnt[i-1]+a[r+i],sum[i]=sum[i-1]+a[r+i]*i;
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
FOR(i,1,K)
{
Q.clear();
FOR(j,1,n)
{
LL x=getX(j-1),y=getY(i,j-1),k=getK(j),c=getC(j);
Q.del(x,y);
Q.push(x,y);
Q.pop(k);
dp[i][j]=Q.Y()-k*Q.X()+c;
}
}
ans=min(ans,dp[K][n]);
}
printf("%lld\n",ans);
return 0;
}