[CF] C. Vasya And The Mushrooms - Educational Codeforces Round 48 (Rated for Div. 2)

https://codeforces.com/contest/1016/problem/C

题目大意

给出一个 $2 \times n$ 的矩阵,矩阵上每个位置有一个数字,代表每秒会多出 $a_{i, j}$ 的价值。第 $0s$ 从左上角出发,每次到达一个格子的时刻取到当前的价值,每一秒要强制走到某一个相邻的格子(四联通),问不重复的走完所有格子所能取到的最好代价是多少。

$1 \le n \le 3 \times 10^5$。$1 \le a_{i, j} \le 10^6$。

简要题解

观察:

想从左上角出发走完所有格子只有如下一种模式:

v > v > > > > v
> ^ > ^ < < < <

所以我们只要去枚举从上下反复,到左右走到头的变化的位置即可。

我们注意到贡献的形式是 $val_0 * 0 + val_1 * 1 + val * 2$ 的形式。对于左侧上下跳的部分我们可以直接模拟,而注意到右侧是横向的连续一段,对于这样的贡献,我们可以预处理两个前缀和 $\sum val_i$ 和 $\sum val_i * i$。然后对于对应的段,我们用 $\sum val_i$ 的倍数把值调整到我们想要的值即可。

复杂度

$T$:$O(n)$

$S$:$O(n)$

代码实现

#include <bits/stdc++.h>
using namespace std;

int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();

using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;

template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) { 
    return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) { 
    return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z 
    if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
    if(x<z) { y=x; x=z; } else if(y<z) y=z; }

// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());

/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/

void solve() {
  int n; cin >> n;
  vector<vector<LL>> a(2, vector<LL>(n));
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < n; j++) {
      cin >> a[i][j];
    }
  }

  vector<vector<LL>> sum(2, vector<LL>(n));
  vector<vector<LL>> sumil(2, vector<LL>(n));
  vector<vector<LL>> sumir(2, vector<LL>(n));
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < n; j++) {
      sum[i][j] = a[i][j] + (j ? sum[i][j - 1] : 0);
      sumil[i][j] = a[i][j] * j + (j ? sumil[i][j - 1] : 0);
    }
  }
  for (int i = 0; i < 2; i++) {
    sumir[i][n - 1] = a[i][n - 1] * n + sumil[i ^ 1][n - 1];

    for (int j = n - 2; j >= 0; j--) {
      sumir[i][j] = a[i][j] * (n + n - 1 - j) + sumir[i][j + 1];
    }
  }
  
  auto getsum = [&](int i, int l, int cnt) -> LL {
    LL ans = sum[0][n - 1] + sum[1][n - 1];
    if (l) ans -= sum[0][l - 1] + sum[1][l - 1];

    LL diff = cnt - l;
    ans *= diff;
    ans += sumir[i ^ 1][l];
    if (l) ans -= sumil[i][l - 1];

    return ans;
  };

  LL ans = 0;
  LL cur = 0;
  LL cnt = 0;
  for (int j = 0; j < n; j++) {
    if (j & 1) {
      cmax(ans, cur + getsum(1, j, cnt));
      cur += a[1][j] * cnt;
      cnt++;
      cur += a[0][j] * cnt;
      cnt++;
    } else {
      cmax(ans, cur + getsum(0, j, cnt));
      cur += a[0][j] * cnt;
      cnt++;
      cur += a[1][j] * cnt;
      cnt++;
    }
    // cerr << j << ' ' << cnt << ' ' << cur << ' ' << ans << endl;
  }
  cout << ans << '\n';
}

int main() {
  int t = 1; 
  // cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}
Prev: [CF] B. Segment Occurrences - Educational Codeforces Round 48 (Rated for Div. 2)
Next: [CF] E. Mycraft Sand Sort - Codeforces Round 1005 (Div. 2)