这一场的A题坑了我好久,A了A题之和把B和C迅速交完就开始坐牢了,靠。
题解:
A Game
题目要求最多一次不相邻跨越,就是这个地方被坑了。
双指针求一次左右两边可以缩减到的最多的位置
#include <bits/stdc++.h>
const int N = 2e5 + 111;
#define int long long
using namespace std;
int n, m, t;
int f[N], g[N];
signed main() {
cin >> t;
while (t --) {
cin >> n;
for (int i = 1; i <= n; ++ i)
cin >> g[i];
int l = 1, r = n - 1, ans;
while (l <= n && g[l]) l ++;
if (l < n) {
ans = n - l + 1;
while (g[r]) r--, ans--;
cout << ans << endl;
} else cout << 0 << endl;
}
return 0;
}
B Game of Ball Passing
思维题,传球数目最少。
我们可以发现,如果先有一个求,传给所有人,使其大部分人都传球次数为0,此时,如果最大的传球次数的那个人次数不为0,那么就要再传不为0的这个数这么多次。
特判 0 0
#include <bits/stdc++.h>
const int N = 2e5 + 111;
#define int long long
using namespace std;
int n, m, t;
int f[N], g[N];
signed main() {
cin >> t;
while (t --) {
cin >> n;
int sum = 0, ma = 0, x;
for (int i = 1; i <= n; ++ i)
cin >> x, sum += x, ma = max (x, ma);
if (ma > sum - ma) cout << 2 * ma - sum << endl;
else if (sum == 0) cout << 0 << endl;
else cout << 1 << endl;
}
return 0;
}
C Weird Sum
颜色c最多只有 1 0 5 10^5 105种,开个map当桶,存一下每一种颜色下的坐标集合。
如何求其两两之间的曼哈顿距离。这个地方是 n 2 n ^ 2 n2的
对于求距离是,其实形如这种:
∣ x 1 − x 2 ∣ + ∣ x 1 − x 3 ∣ + ∣ x 1 − x 4 ∣ + ∣ x 2 − x 3 ∣ + ∣ x 2 − x 4 ∣ + ∣ x 3 − x 4 ∣ |x_1 - x_2| + |x_1 - x_3| + |x_1-x_4| + |x_2 - x_3| + |x_2-x_4|+|x_3-x_4| ∣x1−x2∣+∣x1−x3∣+∣x1−x4∣+∣x2−x3∣+∣x2−x4∣+∣x3−x4∣
如果我们从大到小把x排序之后,绝对值就可以去掉
即: 3 x 1 + 2 x 2 + x 3 − 3 x 4 − 2 x 3 − x 2 3x_1+2x_2+x3-3x_4-2x_3-x_2 3x1+2x2+x3−3x4−2x3−x2
对于y也是这种形式的处理掉,则可以把n优化掉
#include <bits/stdc++.h>
const int N = 2e5 + 111;
#define int long long
using namespace std;
int n, m, t, ans;
unordered_map<int, vector<pair<int, int>>> mp;
signed main() {
cin >> n >> m;
for (int i = 1, x; i <= n; ++ i)
for (int j = 1; j <= m; ++ j)
cin >> x, mp[x].push_back({i, j});
for (auto [_, x] : mp) {
if (x.size() == 1) continue;
auto ve = x;
sort(ve.begin(), ve.end(),
[](pair<int, int>& a, pair<int, int>& b) {
return a.first > b.first;
});
int xx = 0, siz = ve.size();
for (int i = 1; i <= siz; ++ i) {
xx += ve[i - 1].first * (siz - i);
xx -= ve[siz - i].first * (siz - i);
}
ans += xx;
sort(ve.begin(), ve.end(),
[](pair<int, int>& a, pair<int, int>& b) {
return a.second > b.second;
});
int yy = 0;
for (int i = 1; i <= siz; ++ i) {
yy += ve[i - 1].second * (siz - i);
yy -= ve[siz - i].second * (siz - i);
}
ans += yy;
}
cout << ans << endl;
return 0;
}
D Integral Array
赛后补的题,题目要求是任意一个 ⌊ y x ⌋ \lfloor\frac{y}{x}\rfloor ⌊xy⌋的值也在数组中出现过,
直接暴力做时间复杂度很美妙。
仔细观察会发现值的范围不是很大,才 1 0 6 10^6 106内的数,所以可以考虑向这方面下手
对于任意一个 ⌊ y x ⌋ = k \lfloor\frac{y}{x}\rfloor = k ⌊xy⌋=k 则 k x ≤ y ≤ ( k + 1 ) x − 1 kx\leq y \leq (k + 1)x - 1 kx≤y≤(k+1)x−1
而我们需要判断的就是是不是在这一段内可能出现这样的值,这里可以采用的是前缀和累计数组内所有元素在某个区间内出现的个数。
对于 1 1 1到 1 0 6 10^6 106内的任何一个数组中的数的 k k k倍, 如果在这个 k x ≤ y ≤ ( k + 1 ) x − 1 kx\leq y \leq (k + 1)x - 1 kx≤y≤(k+1)x−1区间内出现过数组内的元素,而数组内没有 k k k这个元素,那么就代表不符合条件
因为 前提满足了 x x x和 y y y的存在,可 k k k不存在,即不符合条件
#include <bits/stdc++.h>
const int N = 1e6 + 111;
using namespace std;
int mp[N], s[N], g[N], t, n, m;
int main() {
cin >> t;
while (t --) {
int f = 1;
cin >> n >> m;
for (int i = 0; i <= m; ++ i)
mp[i] = 0;
for (int i = 1; i <= n; ++ i)
cin >> g[i], mp[g[i]] ++;
for (int i = 1; i <= m; ++ i)
s[i] = s[i - 1] + mp[i];
for (int i = 1; i <= m && f; ++ i) {
if (!mp[i]) continue;
for (int j = i; j <= m && f; j += i) {
int l = j - 1, r = min (m, j + i - 1);
if (s[r] - s[l] > 0 && !mp[j / i])
f = 0;
}
}
cout << (f ? "YES" : "NO") << endl;
}
return 0;
}