思维+前缀和
有生之年第一次做出C,WA了7发qwq,激动的要哭惹
题目大意
从 ( 0 , 0 ) (0,0) (0,0) 到 ( n , n ) (n,n) (n,n),可以向右或向上走,每次的线段有花费,求最小花费。
解题思路
对于向右的线段,最优方法一定是花费最少的线段走最长,其他的都走最短(即走 1 1 1)。处理的时候就记录当前最小的 c i c_i ci,用前缀和优化。
对于向上的同理。
具体解题的时候遍历所有的 c i c_i ci,如 c 1 , c 2 , c 3 c_1,c_2,c_3 c1,c2,c3,那么看作 c 1 , c 3 c_1,c_3 c1,c3 是向右, c 2 c_2 c2 是向左,分别处理即可。
注意事项
1.不开 l o n g l o n g long \ long long long 见祖宗~
参考代码
#include<stdio.h>
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<deque>
#include<map>
#include<unordered_map>
#include<set>
#include<stack>
//#define LOCAL //提交时一定注释
#define VI vector<int>
#define eps 1e-8
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
typedef long long LL;
typedef double db;
const int inf = 0x3f3f3f3f;
const LL INF = 1e18;
const int N = 1e5 + 10;
inline int readint() {int x; scanf("%d", &x); return x;}
int c[N];
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int t = readint();
while (t--) {
int n = readint();
for(int i = 0; i < n; ++i) {
c[i] = readint();
}
LL a = INF; //记录答案
LL sum1 = c[0], sum2 = c[1]; //分别为两个部分的前缀和
int min1 = c[0], min2 = c[1]; //分别为两个部分的最小值
LL a1 = 1LL * min1 * n, a2 = 1LL * min2 * n; //两个部分的答案
a = a1 + a2;
// cout << "a1:" << a1 << " " << "a2:" << a2 << endl;
for(int i = 2; i < n; ++i) {
if (!(i & 1)) { //分别处理即可
sum1 += 1LL * c[i];
if (c[i] < min1) {
min1 = c[i]; //更新最小值
}
a1 = 1LL * (sum1 - min1) + 1LL * min1 * (n - (i / 2)); //更新此时这部分的答案
}
else {
sum2 += 1LL * c[i];
if (c[i] < min2) {
min2 = c[i];
}
a2 = 1LL * (sum2 - min2) + 1LL * min2 * (n - (i / 2));
}
a = min(a, a1 + a2); //更新最终的答案
}
printf("%lld\n", a);
}
return 0;
}