题面描述
思路
排序之后显而易见的状态转移方程
决策单调性
自己证明。
踢队头
此时, 优于
可以发现,队列应维护一个下凸壳。
踢队尾
由于维护一个下凸壳,
所以
反之,
当
踢去队尾。
AC code
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define ll long long
#define gc getchar()
using namespace std;
const int N=1e4+10;
const int M=5e3+10;
inline void qr(int &x)
{
x=0;char c=gc;int f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
int f[N],g[N],a[N];
int q[N],l,r;
inline int calc(int j,int k)
{
return g[k]-g[j]+a[k+1]*a[k+1]-a[j+1]*a[j+1];
}
inline int sum(int j,int k)
{
return a[k+1]-a[j+1];
}
bool pd(int i,int j,int k)
{
return calc(j,i)*sum(k,j)<=calc(k,j)*sum(j,i);
}
int main()
{
int t;scanf("%d",&t);int T=0;
while(t--)
{
++T;
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)qr(a[i]);
sort(a+1,a+n+1);
int tot=0;
for(int i=1;i<=n;i++)if(!tot||a[tot]!=a[i])a[++tot]=a[i];
n=tot;
for(int i=1;i<=n;i++)f[i]=(a[i]-a[1])*(a[i]-a[1]);
for(int i=2;i<=m;i++)
{
l=1;r=1;q[1]=i-1;memcpy(g,f,sizeof(g));
for(int j=i;j<=n;j++)
{
while(l<r&&calc(q[l],q[l+1])<=2*a[j]*sum(q[l],q[l+1]))++l;
f[j]=g[q[l]]+(a[j]-a[q[l]+1])*(a[j]-a[q[l]+1]);
while(l<r&&pd(j,q[r],q[r-1]))--r;
q[++r]=j;
}
}
printf("Case %d: %d\n",T,f[n]);
}
return 0;
}