感觉这题还是挺迷的。。。
并不会证这个玩意为什么是对的。。。
固定第一个点的值,其他点的值取a[i]-(i-1)*d(这个点能取的最小值)
然后每次找一个后缀,把这个后缀所有数加一个大于0的值,且保证这是最优的取法下加的尽量大的值。
由于每次把一个数加到最值所以复杂度是
O(n2)
的。
#include <bits/stdc++.h>
using namespace std;
#define N 51000
#define ll long long
int T,n,d;
int a[N];
ll b[N],val,inf,num,pos,mx,tar,ans;
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
if(abs(a[n]-a[1])>(ll)d*(n-1))
{puts("impossible");continue;}
b[1]=a[1];
for(int i=2;i<=n;i++)
b[i]=b[i-1]-d;
inf=1e18;
while(b[n]!=a[n])
{
val=inf;mx=-inf;num=0;
for(int i=n;i>1;i--)
{
if(b[i]<a[i])
val=min(val,a[i]-b[i]),num++;
else num--;
if(num>mx&&b[i]!=b[i-1]+d)
mx=num,pos=i,tar=val;
}
tar=min(tar,b[pos-1]+d-b[pos]);
for(int i=pos;i<=n;i++)
b[i]+=tar;
}
ans=0;
for(int i=1;i<=n;i++)
ans+=abs(a[i]-b[i]);
printf("%lld\n",ans);
}
return 0;
}