题意
记 s u m sum sum为一个多重集的所有元素的和
我们这样定义一个多重集是平衡的:
对于 s u m sum sum的每一个数位,多重集中至少有一个元素与 s u m sum sum此数位相同
现在,给你一个a数组,有两种操作
-
修改a数组中一个位置的值
-
询问 [ l , r ] [l,r] [l,r]区间所有数构成的集合的子集中所有不平衡多重集的 s u m sum sum的最小值(不一定要由连续元素构成)
思路
空集是平衡集,只有一个元素的集合也是平衡集。
然后尝试向其中加入元素,发现只要不出现两个数在某一位上都非零,那这个集合仍旧平衡,否则就不平衡了。
然后题解中的证明我觉得没有必要。只用说明一个元素个数大于2的不平衡集一定可以有一个大小为2的不平衡子集,因为一定存在两个数某位都非零,把这两个取出来就好了。
那么只需要考虑大小为2的集合就行了。问题就转化为了在区间里找两个数,这两个数有至少一位都非零,并且和最小。使用线段树维护。
我看错题意看成必须要连续区间,貌似还需要一个求和的线段树再加上9个set。。。死了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, E = 10, inf = 2e9 + 7;
struct Min_tr{
#define ls (u<<1)
#define rs (u<<1^1)
int t[N<<2][E], ans[N<<2];
void push_up(int u){
ans[u] = min(ans[ls], ans[rs]);
for (int i = 0; i < E; ++ i){
t[u][i] = min(t[ls][i], t[rs][i]);
if (t[ls][i] < inf && t[rs][i] < inf)
ans[u] = min(ans[u], t[ls][i] + t[rs][i]);
}
}
void chg(int u, int x){
int tmp = x;
for (int i = 0; i < E; ++ i){
if (tmp % 10) t[u][i] = x;
else t[u][i] = inf;
tmp /= 10;
}
ans[u] = inf;
}
void build(int u, int l, int r, int *a){
if (l == r){
chg(u, a[l]);
return;
}
int mid = l + r >> 1;
build(ls, l, mid, a);
build(rs, mid+1, r, a);
push_up(u);
}
void modify(int u, int l, int r, int P, int X){
if (l == r){
chg(u, X);
return;
}
int mid = l + r >> 1;
if (P <= mid) modify(ls, l, mid, P, X);
else modify(rs, mid+1, r, P, X);
push_up(u);
}
pair<int, int> merge(pair<int, int> x, pair<int, int> y){
pair<int, int> ret;
ret.first = min(x.first, y.first);
ret.second = min(x.second, y.second);
if (x.second < inf && y.second < inf)
ret.first = min(ret.first, x.second + y.second);
return ret;
}
pair<int, int> query(int u, int l, int r, int L, int R, int X){
if (L <= l && r <= R)
return make_pair(ans[u], t[u][X]);
int mid = l + r >> 1;
pair<int, int> ret = make_pair(inf, inf);
if (L <= mid) ret = merge(ret, query(ls, l, mid, L, R, X));
if (mid < R) ret = merge(ret, query(rs, mid+1, r, L, R, X));
return ret;
}
#undef ls
#undef rs
}t;
int n, q, a[N];
int main()
{
ios::sync_with_stdio(false);
cin >> n >> q;
for (int i = 1; i <= n; ++ i)
cin >> a[i];
t.build(1, 1, n, a);
for (int i = 1; i <= q; ++ i){
int opt, x, y;
cin >> opt >> x >> y;
if (opt == 1){
t.modify(1, 1, n, x, y);
}
else{
int ans = inf;
for (int i = 0; i < E; ++ i)
ans = min(ans, t.query(1, 1, n, x, y, i).first);
if (ans == inf) cout << -1 << endl;
else cout << ans << endl;
}
}
return 0;
}