HNOI 2019 简要题解

fish

枚举 A D AD AD B C BC BC 的限制相当于 A D AD AD B C BC BC 中垂线且 B C BC BC 中点在 A D AD AD 上,预处理所有中垂线,排序之后二分即可; E F EF EF 的限制可以双指针扫一下。

#include <bits/stdc++.h>

using namespace std;

struct point {
  int x, y;

  point(int x = 0, int y = 0): x(x), y(y) {
  }

  point operator + (const point &other) const {
    return point(x + other.x, y + other.y);
  }

  point operator - (const point &other) const {
    return point(x - other.x, y - other.y);
  }

  bool operator < (const point &other) const {
    return x < other.x || (x == other.x && y < other.y);
  }

  long long len() const {
    return (long long) x * x + (long long) y * y;
  }

  int where() const {
    return y > 0 || (y == 0 && x < 0);
  }
};

long long dot(point a, point b) {
  return (long long) a.x * b.x + (long long) a.y * b.y;
}

long long cross(point a, point b) {
  return (long long) a.x * b.y - (long long) a.y * b.x;
}

struct line {
  point v;
  point p;

  line(point v, point p): v(v), p(p) {
  }

  bool operator < (const line &other) const {
    if (v < other.v || other.v < v) {
      return v < other.v;
    } else if (dot(v, p) != dot(other.v, other.p)) {
      return dot(v, p) < dot(other.v, other.p);
    } else {
      return p < other.p;
    }
  }
};

point norm(point p) {
  int d = __gcd(p.x, p.y);
  p.x /= d;
  p.y /= d;
  if (p.x < 0 || (p.x == 0 && p.y < 0)) {
    p.x *= -1;
    p.y *= -1;
  }
  return p;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin >> n;
  vector<point> p(n);
  for (int i = 0; i < n; ++i) {
    cin >> p[i].x >> p[i].y;
  }
  vector<line> lines;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < i; ++j) {
      lines.emplace_back(norm(p[i] - p[j]), p[i] + p[j]);
    }
  }
  sort(lines.begin(), lines.end());
  long long ans = 0;
  for (int i = 0; i < n; ++i) {
    vector<point> q;
    for (int j = 0; j < n; ++j) {
      if (j != i) {
        q.push_back(p[j] - p[i]);
      }
    }
    sort(q.begin(), q.end(), [&](const point &a, const point &b) {
      if (a.where() != b.where()) {
        return a.where() < b.where();
      } else {
        return cross(a, b) > 0;
      }
    });
    for (int j = 0; j < n - 1; ++j) {
      q.push_back(q[j]);
    }
    unordered_map<long long, int> cnt;
    int ways_ef = 0;
    for (int j = 0, l = 0, r = 0; j < n - 1; ++j) {
      while (cross(q[j], q[r]) > 0 || (cross(q[j], q[r]) == 0 && r < n - 1) || dot(q[j], q[r]) < 0) {
        ways_ef += cnt[q[r++].len()]++;
      }
      while (l < r && dot(q[j], q[l]) >= 0) {
        ways_ef -= --cnt[q[l++].len()];
      }
      if (ways_ef) {
        point foo = norm(point(q[j].y, -q[j].x)), bar = p[i] + p[i], baz = (p[i] + q[j]) + (p[i] + q[j]);
        if (baz < bar) {
          swap(bar, baz);
        }
        int ways_bc = lower_bound(lines.begin(), lines.end(), line(foo, baz)) - upper_bound(lines.begin(), lines.end(), line(foo, bar));
        ans += (long long) ways_bc * ways_ef;
      }
    }
  }
  cout << ans * 4 << "\n";
  return 0;
}

jojo

离线建树,然后暴力kmp跳fail,fail可以划分成若干段等差数列,注意失配的时候需要用到这样一个性质:假设周期是 l l l ,对于 i &gt; 2 l i&gt;2l i>2l f a i l i = i − l fail_i = i-l faili=il ,失配的时候特判掉这种情况,复杂度就对了。具体证明可以参见吴瑾昭集训队论文。

#include <bits/stdc++.h>

using namespace std;

const int md = 998244353;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin >> n;
  vector<int> type(n + 1);
  vector<int> repeat(n + 1);
  vector<char> letter(n + 1);
  vector<vector<int>> adj(n + 1);
  for (int i = 1; i <= n; ++i) {
    cin >> type[i];
    if (type[i] == 1) {
      cin >> repeat[i] >> letter[i];
      adj[i - 1].push_back(i);
    } else {
      int from;
      cin >> from;
      adj[from].push_back(i);
    }
  }
  vector<int> foo(1), bar(1), goes(1), right(1);
  vector<long long> sum(1);
  vector<char> let(1);
  int m = 0;
  auto find = [&](int p) {
    return lower_bound(right.begin(), right.end(), p) - right.begin();
  };
  auto get_fail = [&](int p) {
    int q = find(p);
    return foo[q] * p + bar[q];
  };
  auto get_letter = [&](int p) {
    return let[find(p)];
  };
  auto extend = [&](char letter, int repeat) {
    int fail = foo[m] * right[m] + bar[m];
    int l = right[m] + 1, r = right[m] + repeat;
    if (!m) {
      foo.push_back(1);
      bar.push_back(-1);
      goes.push_back(r);
      right.push_back(r);
      sum.push_back((long long) r * (r - 1) / 2);
      let.push_back(letter);
      ++m;
    } else {
      int last = -1;
      for (int i = l; i <= r; ++i) {
        while (fail && letter != get_letter(fail + 1)) {
          int fail_of_fail = get_fail(fail);
          if (fail_of_fail * 2 < fail) {
            fail = fail_of_fail;
          } else {
            int half = fail / 2;
            fail = fail_of_fail;
            if (letter != get_letter(fail + 1)) {
              fail_of_fail = get_fail(fail);
              fail = min(fail_of_fail, fail - half / (fail - fail_of_fail) * (fail - fail_of_fail));
            }
          }
        }
        if (!fail && letter != get_letter(fail + 1)) {
          foo.push_back(0);
          bar.push_back(0);
          goes.push_back(r);
          right.push_back(r);
          sum.push_back(sum.back());
          let.push_back(letter);
          ++m;
          return;
        }
        ++fail;
        if (fail == last) {
          foo.push_back(0);
          bar.push_back(fail);
          goes.push_back(r);
          right.push_back(r);
          sum.push_back(sum.back() + (long long) fail * (r - i + 1));
          let.push_back(letter);
          ++m;
          return;
        }
        int len = min(r - i, goes[find(fail)] - fail);
        foo.push_back(1);
        bar.push_back(fail - i);
        goes.push_back(r);
        right.push_back(i + len);
        sum.push_back(sum.back() + (long long) (i * 2 + len) * (len + 1) / 2 + (long long) (len + 1) * (fail - i));
        let.push_back(letter);
        ++m;
        i += len;
        fail += len;
        last = fail;
      }
    }
  };
  vector<int> ans(n + 1);
  function<void(int)> dfs = [&](int x) {
    int old = m;
    if (type[x] == 1) {
      extend(letter[x], repeat[x]);
    }
    ans[x] = sum[m] % md;
    for (auto y : adj[x]) {
      dfs(y);
    }
    while (m > old) {
      let.pop_back();
      sum.pop_back();
      foo.pop_back();
      bar.pop_back();
      goes.pop_back();
      right.pop_back();
      --m;
    }
  };
  dfs(0);
  for (int i = 1; i <= n; ++i) {
    cout << ans[i] << "\n";
  }
  return 0;
}

polygon

终止态是所有边都连向 n n n ,不难发现第一问一定可以取到下界:没有连向 n n n 的边数。同时可以发现连向 n n n 的边把这个图划分成了若干棵树,相当于求树的拓扑序方案数,显然答案是 n ! / ∏ s i z e i n!/\prod size_i n!/sizei ,直接维护即可。

#include <bits/stdc++.h>

using namespace std;

const int md = (int) (1e9 + 7);

inline int mul(int x, int y) {
  return (int) ((long long) x * y % md);
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int type;
  cin >> type;
  int n;
  cin >> n;
  vector<int> invs(n + 1);
  invs[1] = 1;
  for (int i = 2; i <= n; ++i) {
    invs[i] = mul(md - md / i, invs[md % i]);
  }
  vector<vector<int>> adj(n);
  int turn = 0, ways = 1;
  for (int i = 0; i < n - 3; ++i) {
    int from, to;
    cin >> from >> to;
    --from;
    --to;
    if (from > to) {
      swap(from, to);
    }
    adj[from].push_back(to);
    adj[to].push_back(from);
    if (to != n - 1) {
      ways = mul(ways, ++turn);
      ways = mul(ways, invs[to - from - 1]);
    }
  }
  for (int i = 0; i < n; ++i) {
    adj[i].push_back((i + 1) % n);
    adj[(i + 1) % n].push_back(i);
  }
  cout << turn;
  if (type) {
    cout << " " << ways;
  }
  cout << "\n";
  for (int i = 0; i < n; ++i) {
    sort(adj[i].begin(), adj[i].end());
  }
  int m;
  cin >> m;
  while (m--) {
    int a, b, c, d;
    cin >> a >> c;
    --a;
    --c;
    b = *upper_bound(adj[c].begin(), adj[c].end(), a);
    d = *upper_bound(adj[a].begin(), adj[a].end(), c);
    cout << turn - (d == n - 1);
    if (type) {
      cout << " " << mul(ways, mul(c - a - 1, d == n - 1 ? invs[turn] : invs[d - b - 1]));
    }
    cout << "\n";
  }
  return 0;
}

tour

对同色边和异色边分别保留一棵生成树,如果不是二分图再加一个自环,可以证明答案不变。然后暴力DP即可。

#include <bits/stdc++.h>

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m, tt;
  cin >> n >> m >> tt;
  string s;
  cin >> s;
  vector<vector<vector<int>>> adj(2, vector<vector<int>>(n));
  while (m--) {
    int from, to;
    cin >> from >> to;
    --from;
    --to;
    adj[s[from] != s[to]][from].push_back(to);
    adj[s[from] != s[to]][to].push_back(from);
  }
  vector<vector<vector<int>>> graph(2, vector<vector<int>>(n));
  for (int rep = 0; rep < 2; ++rep) {
    vector<int> color(n, -1);
    for (int i = 0; i < n; ++i) {
      if (color[i] == -1) {
        queue<int> q;
        q.push(i);
        color[i] = 0;
        bool add = false;
        while (!q.empty()) {
          int x = q.front();
          q.pop();
          for (auto y : adj[rep][x]) {
            if (color[y] == -1) {
              graph[rep][x].push_back(y);
              graph[rep][y].push_back(x);
              color[y] = !color[x];
              q.push(y);
            } else if (color[x] == color[y] && !add) {
              graph[rep][i].push_back(i);
              add = true;
            }
          }
        }
      }
    }
  }
  vector<vector<bool>> dp(n, vector<bool>(n));
  queue<pair<int, int>> q;
  for (int i = 0; i < n; ++i) {
    dp[i][i] = true;
    q.emplace(i, i);
  }
  for (int x = 0; x < n; ++x) {
    for (auto y : adj[0][x]) {
      dp[x][y] = true;
      q.emplace(x, y);
    }
  }
  while (!q.empty()) {
    int x = q.front().first, y = q.front().second;
    q.pop();
    for (int rep = 0; rep < 2; ++rep) {
      for (auto xx : graph[rep][x]) {
        for (auto yy : graph[rep][y]) {
          if (!dp[xx][yy]) {
            dp[xx][yy] = true;
            q.emplace(xx, yy);
          }
        }
      }
    }
  }
  while (tt--) {
    int from, to;
    cin >> from >> to;
    --from;
    --to;
    cout << (dp[from][to] ? "YES" : "NO") << "\n";
  }
  return 0;
}

dance

考虑idft的定义式: a n s i = 1 k ∑ j = 0 k − 1 ω k − i j F ( ω k j ) ans_i = \frac{1}{k} \sum_{j=0}^{k-1} \omega_k^{-ij} F(\omega_k^j) ansi=k1j=0k1ωkijF(ωkj) ,用矩阵快速幂求出点值,然后搞个卷积就行了。

#include <bits/stdc++.h>

using namespace std;

int md;

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline int mul(int x, int y) {
  return (int) ((long long) x * y % md);
}

inline int power(int x, int y) {
  int res = 1;
  while (y) {
    if (y & 1) {
      res = mul(res, x);
    }
    x = mul(x, x);
    y >>= 1;
  }
  return res;
}

inline int inv(int a) {
  int b = md, u = 0, v = 1;
  while (a) {
    int t = b / a;
    b -= t * a;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  if (u < 0) {
    u += md;
  }
  return u;
}

namespace fft {
typedef double ld;

const ld pi = acos(-1);

struct num {
  ld x, y;
  
  num(ld x = 0, ld y = 0): x(x), y(y) {
  }

  num operator + (const num &b) const {
    return num(x + b.x, y + b.y);
  }

  num operator - (const num &b) const {
    return num(x - b.x, y - b.y);
  }

  num operator * (const num &b) const {
    return num(x * b.x - y * b.y, x * b.y + y * b.x);
  }
};

num conj(num a) {
  return num(a.x, -a.y);
}

vector<num> fa, fb, roots = {num(0, 0), num(1, 0)};
vector<int> rev = {0, 1};
int base = 1;

void ensure_base(int nbase) {
  if (nbase <= base) {
    return;
  }
  rev.resize(1 << nbase);
  for (int i = 0; i < (1 << nbase); ++i) {
    rev[i] = rev[i >> 1] >> 1 | ((i & 1) << (nbase - 1));
  }
  roots.resize(1 << nbase);
  while (base < nbase) {
    ld angle = 2 * pi / (1 << (base + 1));
    for (int i = 1 << (base - 1); i < 1 << base; ++i) {
      roots[i << 1] = roots[i];
      ld angle_i = angle * ((i << 1) + 1 - (1 << base));
      roots[i << 1 | 1] = num(cos(angle_i), sin(angle_i));
    }
    ++base;
  }
}

void dft(vector<num> &a, int n) {
  int zeros = __builtin_ctz(n);
  ensure_base(zeros);
  int shift = base - zeros;
  for (int i = 0; i < n; ++i) {
    if (i < rev[i] >> shift) {
      swap(a[i], a[rev[i] >> shift]);
    }
  }
  for (int i = 1; i < n; i <<= 1) {
    for (int j = 0; j < n; j += i << 1) {
      for (int k = 0; k < i; ++k) {
        num x = a[j + k], y = a[j + k + i] * roots[i + k];
        a[j + k] = x + y;
        a[j + k + i] = x - y;
      }
    }
  }
}

vector<int> multiply(const vector<int> &a, const vector<int> &b) {
  int need = a.size() + b.size() - 1, nbase = 0;
  while (1 << nbase < need) {
    ++nbase;
  }
  ensure_base(nbase);
  bool equal = a == b;
  int sz = 1 << nbase;
  if (sz > (int) fa.size()) {
    fa.resize(sz);
  }
  if (sz > (int) fb.size()) {
    fb.resize(sz);
  }
  for (int i = 0; i < (int) a.size(); i++) {
    int x = (a[i] % md + md) % md;
    fa[i] = num(x & ((1 << 15) - 1), x >> 15);
  }
  for (int i = a.size(); i < sz; ++i) {
    fa[i] = num(0, 0);
  }
  dft(fa, sz);
  if (equal) {
    for (int i = 0; i < sz; ++i) {
      fb[i] = fa[i];
    }
  } else {
    for (int i = 0; i < (int) b.size(); ++i) {
      int x = (b[i] % md + md) % md;
      fb[i] = num(x & ((1 << 15) - 1), x >> 15);
    }
    for (int i = b.size(); i < sz; ++i) {
      fb[i] = num(0, 0);
    }
    dft(fb, sz);
  }
  ld ratio = 0.25 / sz;
  num r1(1, 0);
  num r2(0, -1);
  num r3(ratio, 0);
  num r4(0, -ratio);
  num r5(0, 1);
  for (int i = 0; i <= sz >> 1; ++i) {
    int j = (sz - i) & (sz - 1);
    num a1 = (fa[i] + conj(fa[j])) * r1;
    num a2 = (fa[i] - conj(fa[j])) * r2;
    num b1 = (fb[i] + conj(fb[j])) * r3;
    num b2 = (fb[i] - conj(fb[j])) * r4;
    if (i != j) {
      num c1 = (fa[j] + conj(fa[i])) * r1;
      num c2 = (fa[j] - conj(fa[i])) * r2;
      num d1 = (fb[j] + conj(fb[i])) * r3;
      num d2 = (fb[j] - conj(fb[i])) * r4;
      fa[i] = c1 * d1 + c2 * d2 * r5;
      fb[i] = c1 * d2 + c2 * d1;
    }
    fa[j] = a1 * b1 + a2 * b2 * r5;
    fb[j] = a1 * b2 + a2 * b1;
  }
  dft(fa, sz);
  dft(fb, sz);
  vector<int> c(need);
  for (int i = 0; i < need; i++) {
    long long aa = fa[i].x + 0.5;
    long long bb = fb[i].x + 0.5;
    long long cc = fa[i].y + 0.5;
    c[i] = (aa + (bb % md << 15) + (cc % md << 30)) % md;
  }
  return c;
}
}

using fft::multiply;

struct matrix {
  vector<vector<int>> a;
  int n;

  matrix(int n): n(n) {
    a = vector<vector<int>>(n, vector<int>(n, 0));
  }

  matrix operator * (const matrix &other) const {
    matrix ans(n);
    for (int k = 0; k < n; ++k) {
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
          add(ans.a[i][j], mul(a[i][k], other.a[k][j]));
        }
      }
    }
    return ans;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m, e, x, y;
  cin >> n >> m >> e >> x >> y >> md;
  --x;
  --y;
  matrix a(n);
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      cin >> a.a[i][j];
    }
  }
  int root = -1;
  {
    vector<int> primes;
    int temp = md - 1;
    for (int i = 2; i * i <= temp; ++i) {
      if (temp % i == 0) {
        primes.push_back(i);
        while (temp % i == 0) {
          temp /= i;
        }
      }
    }
    if (temp != 1) {
      primes.push_back(temp);
    }
    root = 2;
    while (true) {
      bool can = true;
      for (auto p : primes) {
        if (power(root, (md - 1) / p) == 1) {
          can = false;
          break;
        }
      }
      if (can) {
        break;
      }
      ++root;
    }
    root = power(root, (md - 1) / m);
  }
  int inv_root = inv(root);
  vector<int> f(m);
  for (int i = 0, w = 1; i < m; ++i, w = mul(w, root)) {
    matrix b(n), ans(n);
    for (int j = 0; j < n; ++j) {
      for (int k = 0; k < n; ++k) {
        b.a[j][k] = mul(a.a[j][k], w);
        if (j == k) {
          add(b.a[j][k], 1);
          ans.a[j][k] = 1;
        }
      }
    }
    int temp = e;
    while (temp) {
      if (temp & 1) {
        ans = ans * b;
      }
      b = b * b;
      temp >>= 1;
    }
    f[i] = ans.a[x][y];
  }
  vector<int> fact(m * 2 - 1), inv_fact(m * 2 - 1);
  fact[0] = inv_fact[0] = 1;
  for (int i = 1, w = 1, inv_w = 1; i < m * 2 - 1; ++i, w = mul(w, root), inv_w = mul(inv_w, inv_root)) {
    fact[i] = mul(fact[i - 1], w);
    inv_fact[i] = mul(inv_fact[i - 1], inv_w);
  }
  vector<int> foo(m * 2 - 1);
  for (int i = 0; i < m * 2 - 1; ++i) {
    foo[i] = inv_fact[i];
  }
  vector<int> bar(m);
  for (int i = 0; i < m; ++i) {
    bar[i] = mul(f[i], fact[i]);
  }
  reverse(bar.begin(), bar.end());
  vector<int> ans = multiply(foo, bar);
  int inv_m = inv(m);
  for (int i = 0; i < m; ++i) {
    cout << mul(inv_m, mul(ans[i + m - 1], fact[i])) << "\n";
  }
  return 0;
}

sequence

没有修改的做法:维护关于平均数的单调栈,参见高睿泉集训队论文。

有修改的话,维护前后缀单调栈,二分套二分即可。

#include <bits/stdc++.h>

using namespace std;

const int md = 998244353;

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (int) ((long long) x * y % md);
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  cin >> n >> m;
  vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
  }
  vector<long long> sum(n + 1);
  vector<int> sqr(n + 1);
  for (int i = 0; i < n; ++i) {
    sum[i + 1] = sum[i] + a[i];
    add(sqr[i + 1] = sqr[i], mul(a[i], a[i]));
  }
  vector<int> invs(n + 1);
  invs[0] = invs[1] = 1;
  for (int i = 2; i <= n; ++i) {
    invs[i] = mul(md - md / i, invs[md % i]);
  }
  int foo = -1, bar = 0, baz = 0;
  auto get_sum = [&](int l, int r) {
    return sum[r] - sum[l] + (l < foo && foo <= r) * bar;
  };
  auto get_sqr = [&](int l, int r) {
    int ans = baz;
    add(ans, sqr[r]);
    sub(ans, sqr[l]);
    return ans;
  };
  auto check = [&](int l, int r, int ll, int rr) {
    return (__int128) get_sum(l, r) * (rr - ll) < (__int128) get_sum(ll, rr) * (r - l);
  };
  auto get = [&](int l, int r) {
    int x = mul(get_sum(l, r) % md, invs[r - l]);
    int ans = 0;
    add(ans, mul(r - l, mul(x, x)));
    sub(ans, mul(2, mul(get_sum(l, r) % md, x)));
    add(ans, get_sqr(l, r));
    return ans;
  };
  vector<vector<pair<int, int>>> events(n + 1);
  vector<int> ans(m);
  for (int i = 0; i < m; ++i) {
    int foo, bar;
    cin >> foo >> bar;
    events[foo].emplace_back(bar, i);
  }
  vector<vector<int>> erased(n);
  vector<int> suff(n + 1);
  vector<int> stack_suff(1, n);
  int top_suff = 0;
  for (int i = n - 1; ~i; --i) {
    suff[i] = suff[i + 1];
    while (top_suff && check(stack_suff[top_suff], stack_suff[top_suff - 1], i, stack_suff[top_suff])) {
      sub(suff[i], get(stack_suff[top_suff], stack_suff[top_suff - 1]));
      erased[i].push_back(stack_suff[top_suff]);
      stack_suff.pop_back();
      --top_suff;
    }
    add(suff[i], get(i, stack_suff[top_suff]));
    stack_suff.push_back(i);
    ++top_suff;
  }
  vector<int> pref(n + 1);
  vector<int> stack_pref(1, 0);
  int top_pref = 0;
  for (int i = 1; i <= n; ++i) {
    stack_suff.pop_back();
    --top_suff;
    reverse(erased[i - 1].begin(), erased[i - 1].end());
    for (auto j : erased[i - 1]) {
      stack_suff.push_back(j);
      ++top_suff;
    }
    for (auto p : events[i]) {
      foo = i;
      bar = p.first - a[i - 1];
      add(baz, mul(p.first, p.first));
      sub(baz, mul(a[i - 1], a[i - 1]));
      auto query_left = [&](int rr) {
        int l = 0, r = top_pref;
        while (l < r) {
          int mid = (l + r) >> 1;
          int ll = stack_pref[mid];
          if (check(ll, rr, stack_pref[mid], stack_pref[mid + 1])) {
            r = mid;
          } else {
            l = mid + 1;
          }
        }
        return stack_pref[r];
      };
      auto query_right = [&]() {
        int l = 0, r = top_suff;
        while (l < r) {
          int mid = (l + r) >> 1;
          int rr = stack_suff[mid];
          int ll = query_left(rr);
          if (check(stack_suff[mid + 1], stack_suff[mid], ll, rr)) {
            r = mid;
          } else {
            l = mid + 1;
          }
        }
        return stack_suff[r];
      };
      int r = query_right();
      int l = query_left(r);
      add(ans[p.second], get(l, r));
      add(ans[p.second], pref[l]);
      add(ans[p.second], suff[r]);
      foo = -1;
      bar = 0;
      baz = 0;
    }
    pref[i] = pref[i - 1];
    while (top_pref && check(stack_pref[top_pref], i, stack_pref[top_pref - 1], stack_pref[top_pref])) {
      sub(pref[i], get(stack_pref[top_pref - 1], stack_pref[top_pref]));
      stack_pref.pop_back();
      --top_pref;
    }
    add(pref[i], get(stack_pref[top_pref], i));
    stack_pref.push_back(i);
    ++top_pref;
  }
  cout << pref[n] << "\n";
  for (int i = 0; i < m; ++i) {
    cout << ans[i] << "\n";
  }
  return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值