A. X Axis
题意:在一条x轴上给定三个点,找到一个点,使得:
∑
i
=
1
3
∣
x
−
a
i
∣
\sum_{i=1}^{3}|x-ai|
∑i=13∣x−ai∣最大。
解:注意到: 0 < = x < = 10 0<=x<=10 0<=x<=10,故遍历每个点计算即可。
B. Matrix Stabilization
题意:给定一个
n
∗
m
n*m
n∗m的矩阵,找到某个单元格
(
i
,
j
)
(i,j)
(i,j),与它相邻的单元格的值严格小于它的值,然后将该单元格的值一直减小直到不满足严格小于的条件;若有多个这样的单元格,从左到右、从上到下执行。问最后的矩阵如何。
解:若有这样一个单元格,那么这个单元格一定会变成与它相邻的单元格中的最大值。
顺序检查修改即可。
C. Update Queries
题意:给定长度为
n
n
n的字符串
s
s
s和
m
m
m个整数
i
n
d
i
ind_{i}
indi,其中
i
n
d
i
ind_{i}
indi对应
s
s
s中的索引,以及长度为
m
m
m的字符串
c
c
c,可以任意排列
i
n
d
ind
ind数组,按照顺序执行:
s
[
i
n
d
i
]
=
c
[
i
]
s[ind_{i}]=c[i]
s[indi]=c[i],问可以得到字典序最小的字符串
s
s
s。
解:首先可以对字符串 c c c按照字典序排序,因为 i n d ind ind数组可以任意打乱。字符串 s s s中只有 i n d i ind_{i} indi位置上会改变,按照排序后的字符串依次放入即可。需要注意的是我们需要对 i n d ind ind数组去重,因为存在覆盖关系。
AC代码:
void solve()
{
int n, m; cin >> n >> m;
string s; cin >> s;
vector<int> ind(m);
forn (i, 0, m) cin >> ind[i];
set<int> pos;
forn (i, 0, m) pos.insert(ind[i]);
string c; cin >> c;
sort(all(c)); int cnt = 0;
for(auto i : pos) {
s[i - 1] = c[cnt++];
}
cout << s << endl;
}
D. Mathematical Problem
题意:给定长度为
n
n
n的字符串,向其中插入
n
−
2
n-2
n−2个
+
+
+或
×
\times
×,使得运算式结果最小。
解:因为插入 n − 2 n-2 n−2个符号,那么一定有一个两位数 (但值可能只有一位),那么我们可以枚举两位数。我们可以贪心的将每个不为 1 1 1的数加入到结果中,将每个 1 1 1不计入(使用乘号),需要注意的是当我们枚举的这个数为 01 01 01时,需要对答案减一,因为我们可以使用乘号忽略本身。
AC代码:
void solve()
{
int n; cin >> n;
string s; cin >> s;
if(n == 2) {
cout << stoll(s) << endl;
return;
} else {
forn (i, 0, n) {
if(s[i] == '0') {
if(n != 3 || i != 1) {
cout << 0 << endl;
return;
}
}
}
int ans = 1e9;
forn (i, 2, n + 1) {
string c = "";
c.push_back(s[i - 2]), c.push_back(s[i - 1]);
int num = stoll(c);
int flag = 0;
if(num == 1) num = 0, flag = 1;
forn (j, 0, n) {
if(j == i - 2 || j == i - 1) continue;
if(s[j] == '1') {
if(flag) {num += 1; continue;}
else continue;
}
num += s[j] - '0';
}
ans = min(ans, num);
}
cout << ans << endl;
}
}
E. Beautiful Array
题意:给定一个数组
a
a
a和
k
k
k,做任意次如下操作:
a
i
=
a
i
+
k
a_{i}=a_{i}+k
ai=ai+k。定义美丽数组:对于
1
≤
i
≤
n
1\leq i \leq n
1≤i≤n,
b
i
=
b
n
−
i
+
1
b_{i}=b_{n-i+1}
bi=bn−i+1.问至少多少次操作可以将数组
a
a
a变为美丽数组。
解:我们需要两两配对,使得
a
i
=
a
j
+
x
k
a_{i}=a_{j}+xk
ai=aj+xk,即
a
i
≡
a
j
(
m
o
d
k
)
a_{i} \equiv a_{j}(mod \quad k)
ai≡aj(modk),余数相同的可以放入一组中,并记录下
b
i
=
a
i
/
k
b_{i}=a_{i}/k
bi=ai/k。若组中元素数量为偶数,那么按大小排序后顺序两两配对为最优,即
b
2
−
b
1
+
b
4
−
b
3
.
.
.
+
b
m
−
b
m
−
1
b_{2}-b_{1}+b_{4}-b_{3}...+b_{m}-b_{m-1}
b2−b1+b4−b3...+bm−bm−1,
m
m
m为一组中的元素数量;若组中元素数量为奇数,那么有一个无需配对,可以将其删掉并按照偶数的方案计算。可以枚举被删的数字,但如果我们每次都按照这个方案计算,时间复杂度为
O
(
n
2
)
O({n^2})
O(n2),我们无法接受。观察可知,删除第奇数个一定优于删掉第偶数个,如图:
我们可以考虑前缀和来减低复杂度:创建一个
d
d
d数组,
d
i
=
b
i
−
b
i
−
1
d_{i}=b_{i}-b_{i-1}
di=bi−bi−1,创建
s
1
s1
s1和
s
2
s2
s2数组,对于
1
≤
i
<
d
.
s
i
z
e
(
)
1 \leq i < d.size()
1≤i<d.size(),当
i
i
i为奇数时,
s
1
(
i
+
1
)
/
2
=
s
1
(
i
−
1
)
/
2
+
d
i
s1_{(i+1)/2}=s1_{(i-1)/2}+d_{i}
s1(i+1)/2=s1(i−1)/2+di; 当
i
i
i为偶数时,
s
1
i
/
2
=
s
1
(
i
−
1
)
/
2
+
d
i
s1_{i/2}=s1_{(i-1)/2}+d_{i}
s1i/2=s1(i−1)/2+di,这样得到
d
d
d数组奇数索引下的前缀和以及偶数索引下的前缀和。当我们删除第一个数,得到的结果为
d
2
+
d
4
+
.
.
.
d_{2}+d_{4}+...
d2+d4+...,即
s
2
k
s2_{k}
s2k,当我们删除第二个数时,得到的结果为
d
1
+
d
4
+
.
.
.
d_{1}+d_{4}+...
d1+d4+...,即
s
1
1
+
(
s
2
k
−
s
2
1
)
s1_{1}+(s2_{k}-s2_{1})
s11+(s2k−s21),以此类推取
m
i
n
min
min即可。
讨论无解情况:当
n
n
n为偶数时,分组后每个组的元素个数都必须为偶数才能成功配对;当
n
n
n为奇数时,至多一个组的元素个数为奇数,否则无解。
AC代码:
void solve()
{
int n, k, flag; cin >> n >> k;
vector<int> a(n);
forn (i, 0, n) cin >> a[i];
map<int, int> mr;
forn (i, 0, n) mr[a[i] % k]++;
if(n & 1) flag = 1;
else flag = 0;
for(auto &[x, y] : mr) {
if(y % 2 != 0) flag -= 1;
}
if(flag < 0) {
cout << -1 << endl;
return;
}
ll ans = 0; map<int, vector<int>> mp;
forn (i, 0, n) {
mp[a[i] % k].push_back(a[i] / k);
}
for(auto &[x, b] : mp) {
sort(all(b));
if(b.size() % 2 == 0) {
for(int i = 0; i < b.size(); i += 2) {
ans += b[i + 1] - b[i];
}
} else {
if(b.size() != 1) {
vector<int> d(b.size());
forn (i, 1, d.size()) d[i] = b[i] - b[i - 1];
vector<ll> s1(d.size() / 2 + 1), s2(d.size() / 2 + 1);
forn (i, 1, d.size()) {
if(i & 1) s1[(i + 1) / 2] = s1[(i - 1) / 2] + d[i];
else s2[i / 2] = s2[(i - 1) / 2] + d[i];
}
ll num = 1e15;
for(int i = 0; i < b.size(); i += 2) {
int l = i / 2; int r = d.size() / 2;
num = min(num, s2[r] - s2[l] + s1[l]);
}
ans += num;
}
}
}
cout << ans << endl;
}