题目链接
题意:
给出你一个n*n的二维地图,让你从(0,0)走到(n,n)规定:
- 只能向右和向上走,并且向右向上交替进行。
- 每次可以连着走几段,每次走都有一个代价 a i a_i ai(单位长度的代价 )i表示第几次走
- 最后的总代价是每一段走的总代价和。
让你求最小的代价、
思路:
一开始就想到了前缀和优化,只不过一开始光集中的想这最后两步走长点,这样就可以保证一维度最优,另一位都,就不是最优的。简单的说一下,虽然不是正解,但可以从中挖掘(提炼)出正解,就是说我们一共最多要走的是2N单位长度,那么我们维护一维最优的化就是,但我们考虑 i i i次走时。那么我们前面一共是走了 i − 1 i-1 i−1次,我们再往前推一步,就是 i − 2 i-2 i−2那么我们就可保证前面 i − 1 i-1 i−1次都走一单位,最后两步 i 和 i − 1 i和i-1 i和i−1 一定能走到终点。那么i-1走多少步那一共是2n走了i-2步剩 ( 2 ∗ n − i + 2 ) = s u m (2*n-i+2)=sum (2∗n−i+2)=sum步先走的,那么 i − 1 i-1 i−1需要走(sum+1)/2步,i需要走 (sum/2)步。
这就是 单方面一维最优。但是我们保证一维最优,另一维却不一定是最优的。所以说不是正解却能启发我们想到正解。
正解:是二维度最优,我们保证二维都是最小的走的步数最多即可保证最终答案最优。所以需要维护二维中的最小值。那我们每次都都比较,记录一下最小值不就行了,然后维护一次前缀因为前面每一个最小都是需要走一段的。我们再加上两位都最小值还需要走的步数(走到终点),比较取最小值即可。
下面注释的是我原本的错解,看着理解下,提炼出正解嘻嘻。
晚安好梦各位。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
typedef long long ll;
ll a[maxn], b[maxn],c[maxn];
ll n, m, cnt, k1, k2;
map<ll, ll> mp;
ll maxx;
string str;
int main()
{
ll t;
cin >> t;
while(t--)
{
cin >> n;
b[0]=0;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
b[i] = b[i - 1] + a[i];
}
ll ji=a[1],ou=a[2];
maxx =n*a[1]+n*ou;
ll ans=2*n;
for(int i=3;i<=n;i++){
if(i%2)ji=min(ji,a[i]);
else ou=min(ou,a[i]);
ll p,q;
ll sum=ans-i;
p=(sum+1)/2;
q=sum/2;
maxx=min(maxx,b[i]+q*ji+p*ou);
}
/*ll ans = 2 * n;
for(int i = 2; i <= n; i++)
{
ll sum = ans - i + 2;
ll p, q;
p = sum / 2;
q = (sum + 1) / 2;
maxx = min(maxx, b[i - 2] + q * a[i - 1] + p * a[i]);
}*/
cout << maxx << endl;
}
return 0;
}