【比赛总结】ABC 444 总结
前言
差点就 AC E 了,【痛哭.jpg】。
为什么他们都没有 AC C 呢?
A - Repdigit
为什么这种题我第一次还错了!
奶龙错误代码:
if (s[0] == s[1] == s[2]) cout << "Yes";
else cout << "No";
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
if (s[0] == s[1] && s[1] == s[2]) cout << "Yes";
else cout << "No";
return 0;
}
B - Digit Sum
这道题也是无需多评。
#include <bits/stdc++.h>
using namespace std;
int n, k, ans;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
int sum = 0, t = i;
while (t) {
sum += t % 10;
t /= 10;
}
if (sum == k) ans++;
}
cout << ans << endl;
return 0;
}
C - AtCoder Riko
这道题卡了我 \(40\) 分钟!
有若干根初始长度均为 \(L\) 的木棍。一次操作后,每根木棍可能:
- 保持原长度 \(L\);
- 断裂为两根木棍,两根的长度总和为 \(L\)。
给定长度为 \(n\) 的数组 \(a\),请你找出所有可能的 \(L\),使得存在一种操作方式,使得操作后所有木棍的长度恰好与 \(a\) 中的元素一一对应。
首先尝试枚举所有的 \(L\),直接对 \(\sum(a_i)\) 的因数枚举就好了。
由于 \(L\ge \max (a_i)\),对于当前枚举的 \(L\),分成两种情况讨论:
若 \(L=\max(a_i)\),我们将所有 \(a_i=L\) 全都从 \(a\) 中去掉(没有分裂),只处理 \(a_i<L\)。
将剩余元素升序排列,假设有 \(m\) 个元素。那么只要判断 \(L\ge a_i+a_{m-i+1}\) 就可以了。
这是一种直观且正确的做法,如果存在“小 \(+\) 小”与“大 \(+\) 大”都能满足的话,那么“小 \(+\) 大”也可以成功。
若 \(L>\max(a_i)\),仍然如法制炮,只是相比上面要算上 \(a_i=L\) 这些元素。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10;
int n, a[N], ans[N];
signed main() {
cin >> n;
int sum = 0, num = 0;
int amax = 0, bmax = 0, cmax = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
amax = max(amax, a[i]), sum += a[i];
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n / 2; i++)
swap(a[i], a[n - i + 1]);
for (int i = 1, r = n; i <= n; i++) {
if (r < i) break;
if (a[i] == amax) num++;
if (a[i] != amax) bmax = max(bmax, a[i] + a[r]), r--;
}
for (int i = 1, r = n; i <= n; i++) {
if (r < i) break;
cmax = max(cmax, a[i] + a[r]), r--;
}
int cnt = 0;
for (int p = (n + 1) / 2; p <= n; p++) {
if (sum % p) continue;
int L = sum / p;
if (L == amax && L >= bmax) ans[++cnt] = L;
else if (L > amax && L >= cmax) ans[++cnt] = L;
}
sort(ans + 1, ans + cnt + 1);
for (int i = 1; i <= cnt; i++)
cout << ans[i] << " ";
return 0;
}
D - Many Repunit Sum
对于 \(i=1,2,\dots,N\),让 \(B_i\) 表示由 \(A_i\) 个 \(1\) 连接而成的整数。
求 \(\sum_{i=1}^n B_i\),其中 \(1\le N,A_i\le 2\times 10^5\)。
树状数组板题,好吧其实没有那么难。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
const int M = 5e5 + 10;
int n, a[N], tree[M];
int lowbit(int x) {
return x & -x;
}
int get(int x) {
int sum = 0;
while (x) sum += tree[x], x -= lowbit(x);
return sum;
}
void update(int x, int d) {
while (x < M) {
tree[x] += d;
x += lowbit(x);
}
}
int ans[M];
signed main() {
cin >> n;
int mmax = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i], update(a[i], 1);
mmax = max(mmax, a[i]);
}
for (int i = 1; i < M; i++) {
ans[i] += max(0ll, n - get(i - 1));
ans[i + 1] += ans[i] / 10;
ans[i] %= 10;
}
int now = 1;
for (int i = M - 1; i >= 1; i--) {
if (ans[i] != 0) {
now = i;
break;
}
}n
for (int i = now; i >= 1; i--)
cout << ans[i];
return 0;
}
E - Sparse Range
有一个由 \(n\) 个数组成的序列,每一项为 \(a_i\),问有多少个连续区间满足其中任意两项的差的绝对值都大于等于 \(D\)。
形式化:存在多少对 \((l,r)\) 满足 \(|a_i-a_j|\ge D\),其中 \(l\le i,j\le r,1\le n\le 4\times 10^5\)。
双指针被写在题目里面了,对吧。
接着我们用一个 multiset 维护区间里的所有元素,假设又有一个元素 \(x\) 要添加进来。我们只要二分查找 \(\le x\) 的最大值与 \(\ge x\) 的最小值就结束了。
纯套路,比 C 题还水,但是双指针写法习惯如果不好就能调一年。
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int N = 5e5 + 5;
int a[N], n, d, ans;
multiset<int> mul;
bool check(int x) {
auto it1 = mul.lower_bound(x);
auto it2 = mul.upper_bound(x);
bool is = 1;
if (it1 != mul.end()) is = (is & ((*it1) - x >= d));
if (it2 == mul.end() && mul.size()) is = (is & (x - (*mul.rbegin()) >= d));
else if (it2 != mul.begin()) it2--, is = (is & (x - (*it2) >= d));
return is;
}
signed main() {
cin >> n >> d;
for (int i = 1; i <= n; i++)
cin >> a[i];
int l = 1, r = 0;
while (l <= n) {
while (r + 1 <= n && check(a[r + 1])) mul.insert(a[++r]);
ans += (r - l + 1), mul.erase(a[l++]);
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号