n
个线段,每个线段长度为a[i]
,每个的线段的起始点是上一个线段的末位,可以向左或向右放,问这n个线段最后最小覆盖区域长度。
放到[x+1,x+a[i]],终点变为x+a[i]
放到[x−a[i],x−1],终点变为x−a[i]
这题不好想dp数组的含义。
如果dp[i][j]
想成第 i 个到第 j 个线段依序放置后最小的覆盖长度,不好推,没有联系
但我们看每个线段长度不超过1000,可以发现 区间覆盖的范围 就在[-1000,1000],超过1000或-1000的就可以省去了,
于是dp[i][j]
是 放置前 i 个线段后,当前位置在坐标 j 时,覆盖长度的最小值
如果遇到a[i]>=j
,这时要往回放,初始点也要相应移动,记录相对距离就可以。
同时这里第i个线段只与第i-1个线段有关,可以优化一下空间
const int M=1e4+7;
const int N=2e3+7;
ll T,n,a[M],dp[2][N],c,sum;
int main(){
T=read();
while(T--){
n=read(); c=1; sum=inf;
for(int i=1;i<=n;i++) a[i]=read();
for(int i=0;i<N;i++) dp[0][i]=inf;
dp[0][a[1]]=a[1];
for(int i=2;i<=n;i++){
for(int j=0;j<N;j++) dp[c][j]=inf;
for(int j=0;j<N;j++){
if(a[i]>=j) dp[c][0]=min(dp[c][0],a[i]-j+dp[c^1][j]);
else dp[c][j-a[i]]=min(dp[c][j-a[i]],dp[c^1][j]);
if(a[i]+j<N) dp[c][j+a[i]]=min(dp[c][j+a[i]],max(j+a[i],dp[c^1][j]));
}
c^=1;
}
c^=1;
for(int i=0;i<N;i++) sum=min(sum,dp[c][i]);
printf("%lld\n",sum);
}
}