1 条题解

  • 0
    @ 2025-8-24 23:09:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ccxswl
    傻不拉几的

    搬运于2025-08-24 23:09:14,当前版本为作者最后更新于2025-02-04 17:28:45,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P11660 我终将成为你的倒影 题解

    感觉评紫比较合理。

    初步思路

    b500b \le 500,这于 n\sqrt n 相近,启发我们思考关于根号复杂度的做法。

    考虑序列分块。散块暴力,难在整块。

    最终思路

    下取整可以看做取某个数的整数部分。f(x)f(x) 可以看为 $\lfloor \frac x b \rfloor + \lfloor \frac a b \rfloor + [a \bmod b + x \bmod b \ge b]$。

    容易发现,假若 f(x)=f(y)f(x)=f(y),令 $c = \lfloor \frac x b \rfloor - \lfloor \frac y b \rfloor$,那么有必要条件 c1|c| \le 1

    y1=xmodb,y2=ymodb,t=amodby_1 = x \bmod b, y_2 = y \bmod b,t = a \bmod b

    对于 c=0c=0

    • y1+t<by2+t<by_1+t < b \land y_2 + t < by1+tby2+tby_1+t \ge b \land y_2 + t \ge b,即 t<min(by1,by2)t < \min(b-y_1,b-y_2)tmax(by1,by2)t \ge \max(b-y_1,b-y_2)。注意到这两个限制不交叉。

    对于 c=1c=1

    • y1+t<by2+tby_1+t<b\land y_2 + t\ge b,即 by2t<by1b-y_2\le t < b-y_1

    对于 c=1c=-1

    • y1+tby2+t<by_1+t\ge b \land y_2+t<b,即 by1t<by2b-y_1\le t < b-y_2

    发现上述限制都是区间的形式,且 t<bt<b。可以考虑在值域为 bb 的桶上差分,再做前缀和。这样就可以支持 O(1)O(1) 查询整块内的答案。

    bb 很小,可以枚举。为对于每个块枚举所有的 bb,对于所有块内的元素计算 f(Ai)=f(Ai1)f(A_i)=f(A_{i-1}) 的限制,预处理出上述的数组。

    空间复杂度 O(b2nB)O(b^2 \frac n B)BB 为块长。

    预处理时间复杂度 O(bn+b2nB)O(bn+b^2\frac n B)

    注意

    1. 注意整块间的答案也要统计。
    2. 空间 O(b2nB)O(b^2 \frac n B),块长 B=nB=\sqrt n 时卡空间,可以适当调大。
    3. 注意限制本身是否合法,即防止出现左边大于右边。

    为什么 Ai105A_i\le 10^5,感觉复杂度于 AiA_i 没任何关系,可以开到 10910^9

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define IL inline
    #define vec vector
    #define eb emplace_back
    #define bg begin
    #define emp emplace
    #define fi first
    #define se second
    #define bg begin
    #define lb lower_bound
    using dub = double;
    using ubt = long long;
    using pii = pair<int, int>;
    
    IL void ckx(int &x, const int &y) { (x < y) && (x = y); }
    IL void ckm(int &x, const int &y) { (x > y) && (x = y); }
    
    template <typename T = int>
    IL T _R() {
      T s = 0, w = 1;
      char c = getchar();
      while (!isdigit(c)) w = c == '-' ? -1 : 1, c = getchar();
      while (isdigit(c)) s = s * 10 + c - 48, c = getchar();
      return s * w;
    }
    
    const int N = 1e5;
    const dub alpha = 1.3;
    const int B = alpha * sqrt(N);
    const int S = N / B + 1;
    const int K = 500;
    const int maxN = N + 3, maxK = K + 3, maxS = S + 3;
    
    int n, m, x[maxN];
    
    int pos[maxN], L[maxS], R[maxS];
    
    int t[maxS][maxK][maxK];
    
    int main() {
      n = _R(), m = _R();
      for (int i = 1; i <= n; i++) x[i] = _R();
    
      for (int i = 1; i <= n; i++) {
        pos[i] = (i - 1) / B + 1;
        if (!L[pos[i]]) L[pos[i]] = i;
        R[pos[i]] = i;
      }
    
      for (int u = 1; u <= pos[n]; u++) {
        for (int b = 1; b <= K; b++) {
          for (int i = L[u] + 1; i <= R[u]; i++) {
            int c = x[i] / b - x[i - 1] / b;
            if (abs(c) <= 1) {
              int y1 = x[i] % b, y2 = x[i - 1] % b;
              if (c == 0) {
                t[u][b][0]++, t[u][b][min(b - y1, b - y2)]--;
                t[u][b][max(b - y1, b - y2)]++;
              } else if (c == 1) {
                if (y1 >= y2) continue;
                t[u][b][b - y2]++, t[u][b][b - y1]--;
              } else {
                if (y1 <= y2) continue;
                t[u][b][b - y1]++, t[u][b][b - y2]--;
              }
            }
          }
          for (int i = 1; i <= K; i++)
            t[u][b][i] += t[u][b][i - 1];
        }
      }
    
      int ans = 0;
      while (m--) {
        int l = _R(), r = _R(), a = _R(), b = _R();
        l ^= ans, r ^= ans, a ^= ans, b ^= ans;
        if (l >= r) { printf("%d\n", ans = 0); continue; }
        ans = 0;
        if (pos[l] == pos[r]) {
          for (int i = l + 1; i <= r; i++)
            ans += (x[i] + a) / b == (x[i - 1] + a) / b;
        } else {
          for (int i = l + 1; i <= R[pos[l]]; i++)
            ans += (x[i] + a) / b == (x[i - 1] + a) / b;
          for (int i = L[pos[r]] + 1; i <= r; i++)
            ans += (x[i] + a) / b == (x[i - 1] + a) / b;
          for (int i = pos[l] + 1; i < pos[r]; i++)
            ans += t[i][b][a % b];
          for (int i = pos[l]; i < pos[r]; i++)
            ans += (x[R[i]] + a) / b == (x[R[i] + 1] + a) / b;
        }
        printf("%d\n", ans);
      }
    }
    
    • 1

    信息

    ID
    11288
    时间
    1000ms
    内存
    250MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者