此题的难点在于证明,任何一个不平衡的子集一定包含至少一个由两个元素组成的不平衡的集合。
我采用反证法加以证明。假设一个不平衡U的集合由n(n>2)的元素组成,且其所有的两个元素的子集均平衡。首先,两个元素的集合要想平衡,两个元素对应十进制数位上的数字,至少有一个要为0。因此集合U中要想达到所有的两个元素子集均平衡,则每个十进制数位上,至少有n-1个元素在该数位上的数字为0(此处容易证明,留给读者自行证明)。也就是说集合U的n个元素,每个十进制数位上,最多有一个元素在该数位上的数字不为0,这样n个元素的和在该为上的数字要么是0,要么是这个不为0的数字。所有数位都满足这种条件,因此对于集合U来说,必定平衡。与假设矛盾。
因此,任何一个不平衡的子集一定包含至少一个由两个元素组成的不平衡的集合。我们的任务就转变成了寻找由两个元素组成的不平衡的集合的元素和的最小值。
题目的修改操作时对于一个元素进行修改,因此建立一颗单点修改的线段树,即可完成此题。线段树结点内存储的信息为,1)结点区间对应的最优结果best;2)一个数组t[i],存储结点对应的区间,在十进制数位的第i位所有不为0的所有元素中,最小的元素。时间复杂度为O(9*(m+n)*logn)。
具体实现详见代码,个人觉得比较容易理解。
题目链接 CF1217E Sum Queries?
//By querry
#include <bits/stdc++.h>
#pragma warning (disable:4996)
#define INF 2e9
#define MOD 998244353
typedef long long ll;
using namespace std;
int n, m;
typedef struct node {
int t[10], best;
node() {
for (int i = 1; i <= 9; i++) t[i] = INF;
best = INF;
}
}node;
template <typename T>
class SegmentTree_Point {
public:
T *info;
int *list;
SegmentTree_Point() {
info = new T[800005];
list = new int[200005];
}
void build() {
for (int i = 1; i <= n; i++)
update(i, list[i]);//O(9logn)
}
void update(int p, int v, int o = 1, int L = 1, int R = n) {//O(9logn)
int M = (L + R) / 2;
if (L == R) {
int temp = v;
for (int i = 1; i <= 9; i++) {
if (temp % 10)
info[o].t[i] = v;
else info[o].t[i] = INF;
temp /= 10;
}
}
else {
if (p <= M) update(p, v, o * 2, L, M);
else update(p, v, o * 2 + 1, M + 1, R);
info[o] = merge(info[2 * o], info[2 * o + 1]);
}
}
T merge(T &a, T &b) {
T c;
c.best = min(a.best, b.best);
for (int i = 1; i <= 9; i++) {
c.t[i] = min(a.t[i], b.t[i]);
if (a.t[i] < INF && b.t[i] < INF)
c.best = min(c.best, a.t[i] + b.t[i]);
}
return c;
}
T query(int ql, int qr, int o = 1, int L = 1, int R = n) {//O(2logn)
int M = (L + R) / 2;
T a, b;
if (ql <= L && R <= qr) return info[o];
if (ql <= M) a = query(ql, qr, o * 2, L, M);
if (M < qr) b = query(ql, qr, o * 2 + 1, M + 1, R);
return merge(a, b);
}
};
int main() {
scanf("%d%d", &n, &m);
SegmentTree_Point <node> ST;
for (int i = 1; i <= n; i++)
scanf("%d", &ST.list[i]);
ST.build();//O(n*9logn)
for (int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (t == 1) ST.update(x, y);//O(9logn)
else {
node ret = ST.query(x, y);//O(2logn)
if (ret.best < INF) printf("%d\n", ret.best);
else printf("-1\n");
}
}
return 0;
}