题意:在一个二维坐标系中,我们从(0,0)到(n,n),中途最多可以转弯n-1次,当然可以转更少次的弯,每次转弯都有一个消耗值。问到达(n,n)消耗值最小是多少?
思路:
首先,我们发现,奇数和偶数可以单独分开来,他们之间是不影响的。我们很容易就能想到我们可以枚举到达终点的转弯的位置。然后注意,这之后的都没有必要考虑了。(这是一个坑点),对于前面的,我们可以预处理出每个方向的每个位置之前出现数字的最小值。同时计算一下每次转弯的前缀和。之前的步数我们只要走一步就行了。然后剩余的步数都是由每个方向的最小值的走完即可。
这里我还想说的是,我在比赛的时候想的是我直接找出两个方向的最小值不就行了吗?然后之前的走一步,其余的最小值走。但是其实这是错误的。首先,我们某一个方向一旦到达n,那么它最多只能转一次方向了。所以即使取到了一个最小值,那么另一个方向的最小值也不一定能取到。然后,我们知道,这个题目的答案一定是对于某一个方向来说,某一个位置走若干步,其余的位置只能走一步,但是要注意的是这个走若干步的位置不一定是最后那次的,也可能是中间的某一个位置,为什么呢?因为我们这个x和y两个方向的是相互有联系的,不是单独的,所以只考虑一个方向的情况可能会错误。于是,正确的解法应该是枚举最后那次转弯,然后同时维护在这之前的最小值,让那个最小值多走,其他的只走一步就行了。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=120;
ll qk(ll a,ll b,ll p){
if(b==0) return 1;
if(b&1) return a*qk(a,b-1,p)%p;
else{
ll mul=qk(a,b/2,p);
return mul*mul%p;
}
}
ll a[100010],b[100010],sum[100010];
void solve(){
ll n;
cin>>n;
a[0]=1e9+7,b[0]=1e9+7;
for(int i=1;i<=n;i++){
ll x;
cin>>x;
sum[i]=sum[i-1]+x;
a[i]=a[i-1];
b[i]=b[i-1];
if(i&1) a[i]=min(a[i],x);
else b[i]=min(b[i],x);
}
ll ans=1e18;
for(int i=2;i<=n;i++){
ll s=sum[i];
if(i&1){
s=s+(n-i/2-1)*a[i]+(n-i/2)*b[i];
}else{
s=s+(n-i/2)*(a[i]+b[i]);
}
ans=min(ans,s);
}
cout<<ans<<endl;
}
int main(){
//freopen("test.in","r",stdin);
int t;
cin>>t;
while(t--){
solve();
}
fclose(stdout);
return 0;
}