bzoj3745 [COCI2015]スタンダード

bzoj3745 [COCI2015]スタンダード

正の整数の所定のシーケンス\(A_1、\ A_2、\ \ cdots、\ A_N \)を探している、\ [\ displaystyle \ sum_ {I = 1} ^ n個の\ sum_ {J =} ^ N {(J-I + 1)\マックス[I、\の J] \分[I、\のJ]} \]

結果\(^ 9 10 \)モジュロ

\(N \ leq5 \ times10 ^ 5、\ a_iを\ [0、\ 10 ^ 8] \)

分割統治、CDQパーティション


間隔のために、パーティションを考える\([Lは、\ R] \) が見つかりました\(\最大\)ポイント\(POS \) \を([L、\ POS- 1]、\ [POS + 1、\ R&LT] \)再帰が、この効果的に対処しません\(\分\)の貢献をし、パーティションのCDQを考えます

現在の間隔の設定\([L、\ R&LT] \) 再帰的プロセス(\ [\ R&LT、MID + 1] [L \中間]、\)\を、左端点算出\([L、\ミッドを] \) 右端\([中間+ 1、\の R] \) 間隔を拠出

オーダー\(MX = \マックス[P、\ MID]、\のMn = \ [P、\ MID]分\) 逆列挙エンドポイントを左(P \)\ので、(X \)\満足する\(MN \ GE \の分[ミッド+ 1、\ X] \)を最大\(X \)、\ (Y \)されている\(MX \ル\マックス[ミッド+ 1、\ Y] \) 最大\(Y \) 仮定\(X <Y \) 右端ポイント\(Q \)

  1. 場合(Q \当量X \)\、への貢献\(MXの\時間MN \倍 \ displaystyleの\和(Q-P + 1)\)
  2. (X <Q \当量のYの\ \)を、への貢献\(MXの\時間(\ displaystyleの \和((Q-P + 1)倍\ \分[X + 1、\ Q]))\)
  3. \(Y <Q \) への貢献\(\ displaystyleの\和(( Q-P + 1)\時間\分[X + 1、\ Q] \時間は最大[Y + 1、\ Q]を\ )\)

最初の直接のカウント

第二は、元の式に分割することができる\(MXの\時間(\ displaystyleの \和(q個の\時間\分[X + 1、\のQ]) - (I-1)\回\和\分[X + 1 、\ Q] \)

前記\(\ displaystyleの\和\分 [X + 1、\ Q] \) と\(\ displaystyleの\和(q個の \時間\分[X + 1、\ Q])\) 缶\(O(LEN) \)の前処理

同様に第三のオープンな括弧、\(\ displaystyleの\和(\分[X + 1、\ Q] \時間は最大[Y + 1、Q])\ \) および\(\ displaystyleの\和(Q \ 時間\分[X + 1、 \ qは】倍\ \マックス[Y + 1、\ Qを])\) することができるように\(\分[X + 1回\ \ q]は最高[Y + 1、\します\ Qは] \)に変換される\(1 \分[Xの+を、\ Q] \時間\マックス[X + 1、\ Q] \) することもできる\(O(LEN)\)の前処理

\(X \ GEのy \)状況と同じ方法

時間複雑\(O(N \ログN )\)

コード

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

typedef long long ll;
const int maxn = 5e5 + 10, P = 1e9, inf = 1e8;
int n, ans, a[maxn], f1[maxn], f2[maxn], g1[maxn], g2[maxn], s1[maxn], s2[maxn];

inline void chkmax(int &x, int y) {
  if (x < y) x = y;
}

inline void chkmin(int &x, int y) {
  if (x > y) x = y;
}

inline int inc(int x, int y) {
  x += y;
  return x < P ? x : x - P;
}

inline int dec(int x, int y) {
  x -= y;
  return x < 0 ? x + P : x;
}

inline int mul(int x, int y) {
  return 1ll * x * y % P;
}

inline int add(int &x, int y) {
  x += y;
  return x < P ? x : x -= P;
}

void cdq(int l, int r) {
  if (l == r) {
    add(ans, mul(a[l], a[l]));
    return;
  }
  int mid = (l + r) >> 1;
  cdq(l, mid), cdq(mid + 1, r);
  f1[mid] = f2[mid] = g1[mid] = g2[mid] = s1[mid] = s2[mid] = 0;
  for (int i = mid + 1, mx = 0, mn = inf; i <= r; i++) {
    chkmax(mx, a[i]), chkmin(mn, a[i]);
    f1[i] = inc(f1[i - 1], mx);
    g1[i] = inc(g1[i - 1], mn);
    f2[i] = inc(f2[i - 1], mul(mx, i));
    g2[i] = inc(g2[i - 1], mul(mn, i));
    s1[i] = inc(s1[i - 1], mul(mx, mn));
    s2[i] = inc(s2[i - 1], mul(mul(mx, mn), i));
  }
  for (int i = mid, mx = 0, mn = inf, x = mid, y = mid; i >= l; i--) {
    chkmax(mx, a[i]), chkmin(mn, a[i]);
    while (x < r && a[x] >= mn && a[x + 1] >= mn) x++;
    while (y < r && a[y] <= mx && a[y + 1] <= mx) y++;
    int p = min(x, y), q = max(x, y);
    add(ans, dec(dec(s2[r], s2[q]), mul(i - 1, dec(s1[r], s1[q]))));
    add(ans, mul(mul(mx, mn), dec(1ll * (p - mid) * (p + mid + 1) / 2 % P, mul(i - 1, p - mid))));
    if (x < y) {
      add(ans, mul(mx, dec(dec(g2[y], g2[x]), mul(i - 1, dec(g1[y], g1[x])))));
    } else {
      add(ans, mul(mn, dec(dec(f2[x], f2[y]), mul(i - 1, dec(f1[x], f1[y])))));
    }
  }
}

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    scanf("%d", a + i);
  }
  cdq(1, n);
  printf("%d", ans);
  return 0;
}

おすすめ

転載: www.cnblogs.com/Juanzhang/p/10990823.html