思路如下,还有一些细节在注释里
代码:
#include<iostream>
#include<math.h>
using namespace std;
typedef long long ll;
ll presum[100005],odd[100005],even[100005];//odd[i](even[i])表示前i个奇(偶)数段中最小的
int main()
{
int t;
cin>>t;
odd[0]=even[0]=1e10;
while(t--){
int n;
cin>>n;
ll a;
for(int i=1;i<=n;i++){
cin>>a;
presum[i]=presum[i-1]+a;
odd[i]=odd[i-1];
even[i]=even[i-1];//这两句不是多余的,因为当i为偶数时,odd[i]没有值(even同理);如果不想写这两句,则在枚举的时候稍微改变一下即可
if(i%2)
odd[i]=min(odd[i-1],a);
else
even[i]=min(even[i-1],a);
}
ll res=1e18;//两条边最大1e18
for(int i=2;i<=n;i++){//枚举n段,最少是两段
ll tmp;
if(i%2)//如果是奇数段,奇线段比偶线段多1
tmp=presum[i]+odd[i]*(n-i/2-1)+even[i]*(n-i/2);//为什么不是presum[i-2]?因为先把所有边长都当作1,再将最短边继续延长
else//如果是偶数段,奇线段和偶线段个数相等
tmp=presum[i]+odd[i]*(n-i/2)+even[i]*(n-i/2);
res=min(tmp,res);
}
cout<<res<<endl;
}
return 0;
}