Loading

Solution - Codeforces 1217E Sum Queries?

对于这个“好的”的判定条件看起来有点奇怪,不妨结合上题目要求的“最小 \(sum\)”一起考虑。

因为要最小化 \(s_p\),所以一个比较直观的想法是先从选的数个数入手。
考虑到如果选的只有 \(1\) 个数 \(a_i\),那么 \(sum = a_i\),一定是好的,排除。
如果选的是 \(2\) 个数 \(a_i, a_j\),那么有 \(sum = a_i + a_j\)
考虑到加法可能带有进位的操作,但实际上可以通过从低位到高位来讨论解决:

  • 若这一位 \(a_i, a_j\) 均为 \(0\),则这一位一定是好的,那就继续往高位看。
  • 若这一位 \(a_i, a_j\) 有一个为 \(0\),那么这一位也是好的,那就继续往高位看。
  • 若这一位 \(a_i, a_j\) 均不为 \(0\),那么这一位一定是坏的。
    需要注意的是因为是从低位往高位看的,所以下面一定不产生进位,可以暴力枚举每一位的数值,可以知道一定无法匹配上。

于是可以发现的是,只要存在一位满足 \(a_i, a_j\) 在此位均不为 \(0\),那么 \(sum = a_i + a_j\) 就是合法的。

考虑扩展到更多数,能够发现其实越多数限制反而越难满足。
但是此时一个位是坏的肯定也需要满足至少存在一位,非 \(0\) 的个数 \(\ge 2\)

  1. 如果是因为进位导致这一位变坏,那么有进位也需要下面有位的非 \(0\) 的个数 \(\ge 2\)
  2. 如果没有进位,那么只有 \(0, 1\) 个肯定不行,所以肯定需要 \(\ge 2\)

所以可以发现,选更多的数反而不如就选 \(2\) 个。

那么接下来的问题就变为:
找到 \(l\le i, j\le r\),满足存在一位满足 \(a_i, a_j\) 在此位均不为 \(0\),最小化 \(a_i + a_j\)

能够发现此时每一位都是独立的,那么就可以对每一个位去做。
对每一位开一个线段树维护这一位非 \(0\) 的数的最大和次大值,修改和查询对于每颗线段树都问一下就可以了。

时间复杂度 \(\mathcal{O}((n + m)\log n\log_{10} V)\)

#include<bits/stdc++.h>
constexpr int inf = 2e9;
constexpr int maxn = 2e5 + 10;
int n, q;
struct node_t {
   int mn, smn;
   inline node_t(int mn_ = inf, int smn_ = inf) {
      mn = mn_, smn = smn_;
   }
   inline node_t operator + (const node_t &a) const {
      if (mn <= a.mn) {
         return node_t(mn, std::min(smn, a.mn));
      } else {
         return node_t(a.mn, std::min(mn, a.smn));
      }
   }
};
struct segtr {
   node_t tr[maxn * 4];
   inline void update(int x, int y, int k = 1, int l = 1, int r = n) {
      if (l == r) {
         return tr[k] = node_t(y), void();
      }
      int mid = l + r >> 1;
      if (x <= mid) update(x, y, k << 1, l, mid);
      else update(x, y, k << 1 | 1, mid + 1, r);
      tr[k] = tr[k << 1] + tr[k << 1 | 1];
   }
   inline node_t query(int x, int y, int k = 1, int l = 1, int r = n) {
      if (x <= l && r <= y) return tr[k];
      int mid = l + r >> 1;
      if (y <= mid) return query(x, y, k << 1, l, mid);
      if (x  > mid) return query(x, y, k << 1 | 1, mid + 1, r);
      return query(x, y, k << 1, l, mid) + query(x, y, k << 1 | 1, mid + 1, r);
   }
} tr[10];
inline void update(int p, int x) {
   for (int d = 0, x_ = x; d < 10; d++, x_ /= 10) {
      tr[d].update(p, x_ % 10 ? x : inf);
   }
}
int main() {
   scanf("%d%d", &n, &q);
   for (int i = 1, x; i <= n; i++) {
      scanf("%d", &x);
      update(i, x);
   }
   for (int op, x, y; q--; ) {
      scanf("%d%d%d", &op, &x, &y);
      if (op == 1) {
         update(x, y);
      } else {
         int ans = -1;
         for (int d = 0; d < 10; d++) {
            node_t val = tr[d].query(x, y);
            if (val.smn == inf) continue;
            int tot = val.mn + val.smn;
            if (tot < ans || ans == -1) {
               ans = tot;
            }
         }
         printf("%d\n", ans);
      }
   }
   return 0;
}
posted @ 2024-11-12 21:54  rizynvu  阅读(5)  评论(0编辑  收藏  举报