2024-08-10 22:50阅读: 677评论: 0推荐: 6

AtCoder Beginner Contest 366

A - Election 2 (abc366 A)

题目大意

n张票,目前投了 t给高桥, a 给青木。

问剩余票随便分配,是否都是一个结局。

解题思路

考虑最好情况,即剩下票全部投给当前票少的,看看能不能超过对方,会则结局会变,否则不会变。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, t, a;
cin >> n >> t >> a;
if (t > a)
swap(t, a);
int left = n - t - a;
if (t + left > a)
cout << "No" << '\n';
else
cout << "Yes" << '\n';
return 0;
}


B - Vertical Writing (abc366 B)

题目大意

给定n个字符串,把这 n个字符串顺时针旋转 90度,输出。

由于字符串长度不一,可能会出现 st的情况,前面的 都要替换成*

解题思路

手动旋转90度,然后对于每一行,从右往左,一旦碰到字符,后续再碰到 时,替换成 *即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
int m = 0;
vector<string> s(n);
for (auto& i : s) {
cin >> i;
m = max(m, (int)i.size());
}
vector<string> t(m);
reverse(s.begin(), s.end());
for (int i = 0; i < m; ++i) {
for (auto& j : s) {
if (i < j.size()) {
t[i] += j[i];
} else {
t[i] += ' ';
}
}
}
for (auto& i : t) {
bool start = false;
for (int j = i.size() - 1; j >= 0; --j) {
if (i[j] != ' ') {
start = true;
}
if (start && i[j] == ' ') {
i[j] = '*';
}
}
}
for (auto& i : t)
cout << i << '\n';
return 0;
}


C - Balls and Bag Query (abc366 C)

题目大意

q个操作,分三种。

  • 1 x 放入背包一个球,数字x
  • 2 x 从背包拿出一个球,数字x
  • 3 问背包不同数字球的个数

解题思路

map维护一下各个数字球的个数,当map[x]=0时移除该元素,询问就是 map.size()

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int q;
cin >> q;
map<int, int> cnt;
while (q--) {
int op;
cin >> op;
if (op == 1) {
int x;
cin >> x;
cnt[x]++;
} else if (op == 2) {
int x;
cin >> x;
cnt[x]--;
if (cnt[x] == 0)
cnt.erase(x);
} else {
cout << cnt.size() << '\n';
}
}
return 0;
}


D - Cuboid Sum Query (abc366 D)

题目大意

三维数组,回答q个询问,每个询问问一个三维区间和。

解题思路

维护一个三元前缀和,即可O(1)通过容斥原理得到一个三元区间的和。

至于如何容斥出来的,感受下二维的情况,三维就是23个项的相加减,公式即在代码里,其实就是i=01j=01k=01(1)i+j+ksum[xlenx×i][yleny×j][zlenz×k]。这里x就是 rxxlenx就是 lx1,其余字母同理。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<vector<vector<int>>> a(
n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1)));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
cin >> a[i][j][k];
}
}
}
vector<vector<vector<int>>> sum(
n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1)));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
sum[i][j][k] = a[i][j][k] + sum[i - 1][j][k] +
sum[i][j - 1][k] + sum[i][j][k - 1] -
sum[i - 1][j - 1][k] - sum[i - 1][j][k - 1] -
sum[i][j - 1][k - 1] + sum[i - 1][j - 1][k - 1];
}
}
}
int q;
cin >> q;
while (q--) {
int lx, rx, ly, ry, lz, rz;
cin >> lx >> rx >> ly >> ry >> lz >> rz;
int ans = sum[rx][ry][rz] - sum[lx - 1][ry][rz] - sum[rx][ly - 1][rz] -
sum[rx][ry][lz - 1] + sum[lx - 1][ly - 1][rz] +
sum[lx - 1][ry][lz - 1] + sum[rx][ly - 1][lz - 1] -
sum[lx - 1][ly - 1][lz - 1];
cout << ans << '\n';
}
return 0;
}


E - Manhattan Multifocal Ellipse (abc366 E)

题目大意

二维平面。给定n个点(xi,yi)

给定D,问有多少个坐标 (x,y),满足i=1n(|xxi|+|yyi|)D

解题思路

从求和式子可以看出x,y是相互独立的,i=1n(|xxi|+|yyi|)=i=1n|xxi|+i=1n|yyi|)D,我们可以分别考虑 x,y轴的情况。

注意到点坐标范围只有 [106,106] ,我们可以直接枚举xy的值,由于D106,可以粗略算出来x,y的范围不会超过[2e6,2e6]

因此,我们直接枚举每个x2e62e6,计算得到 i=1n|xxi|的值 。而计算这个值可以O(1)O(logn)算出来,即把绝对值去掉,即xi<x(xxi)+xix(xix)。我们对xi排序,然后可以二分x或者枚举x时动态维护这个边界点,同时维护前缀和presum后缀和sufsum,以及边界点前面的点数it,那么 xi<x(xxi)+xix(xix)=itxpresum+sufsum(nit)x

这样就算出了每个xi=1n|xxi|,同理计算出每个 yi=1n|yyi|

剩下的问题就是从x里选一个 x,从 y里选一个 y ,有x+yD,有多少对。

这就是个经典问题,先对两个 排序,然后依次枚举 x,那么 yDsum1的都是满足的,可以二分这个边界点,或者双指针维护一下得到满足条件的y的数量,累计即为答案。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, d;
cin >> n >> d;
vector<int> x(n), y(n);
for (int i = 0; i < n; ++i)
cin >> x[i] >> y[i];
auto solve = [&](vector<int>& a) {
sort(a.begin(), a.end());
vector<LL> dis;
int up = 2e6;
int it = 0;
LL presum = 0, sufsum = accumulate(a.begin(), a.end(), 0ll);
for (int i = -up; i <= up; ++i) {
LL sum = 0;
while (it < n && a[it] < i) {
presum += a[it];
sufsum -= a[it];
++it;
}
sum = 1ll * it * i - presum + sufsum - 1ll * (n - it) * i;
dis.push_back(sum);
}
sort(dis.begin(), dis.end());
return dis;
};
auto dis1 = solve(x);
auto dis2 = solve(y);
LL ans = 0;
int it = dis2.size() - 1;
for (auto i : dis1) {
while (it >= 0 && dis2[it] + i > d)
--it;
ans += it + 1;
}
cout << ans << '\n';
return 0;
}


F - Maximum Composition (abc366 F)

题目大意

给定n个一次函数 fi(x)=aix+bi

选择 k(10)个不同的一次函数,使得 fp1(fp2(...fpk(1)))最大。

解题思路

注意到ai>0,bi>0,如果允许 重复选函数的话,因为x越大, f(x)越大,因此每次肯定选,使得fi(x)值最大的函数fi 。但这里不允许重复。

不允许重复,会产生什么问题呢?比如一个函数f1(x)=10x+1 ,另一个函数f2(x)=x+9,如果按照上述方法,结果就是f2(f1(1))=f2(11)=20,然而反过来则是 f1(f2(1))=f1(10)=101。即函数 f1虽然在第一步使用,可以得到最大的 f,但后使用,可以变得更大。因此,如果最后我会选f1f2f2会优先使用,f1会后使用。

这里就出现了函数之间,选择的偏序(顺序)问题。这个偏序怎么定义呢?函数fi,fj ,如果fi(fj(x))>fj(fi(x)),则有 ai(ajx+bj)+biaj(aix+bi)+bj,我们把 i,j分离在一左一右,得到 ai1biaj1bj

这意味着说,如果ai1biaj1bj,则fi(fj(x))>fj(fi(x)),即我先用fj,再用 fi

有了这个函数使用的偏序有什么用呢?题目要使值最大,不仅要考虑选哪 k个函数,还要考虑这 k个函数复合的顺序。而现在我们已经有了一个最优复合顺序了,那剩下的问题就是选哪 k个函数。这其实就是一个选或不选的背包问题了。

先对 fi按照 ai1bi从小到大排序,然后设dp[i][j]表示考虑前 i个函数,已经使用了 j个函数的最大函数值。转移则考虑当前函数选或不选,从dp[i1][j1]dp[i1][j]转移即可。初始条件 dp[0][0]=1

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
vector<array<int, 2>> f(n);
for (auto& [a, b] : f)
cin >> a >> b;
sort(f.begin(), f.end(),
[](const array<int, 2>& a, const array<int, 2>& b) {
auto& [a1, b1] = a;
auto& [a2, b2] = b;
return (a2 - 1) * b1 > (a1 - 1) * b2;
});
vector<LL> dp(k + 1, 0);
dp[0] = 1;
for (int i = 0; i < n; ++i) {
auto& [a, b] = f[i];
vector<LL> dp2 = dp;
for (int j = 1; j <= k; ++j) {
dp2[j] = max(dp2[j], a * dp[j - 1] + b);
}
dp.swap(dp2);
}
cout << dp[k] << '\n';
return 0;
}


G - XOR Neighbors (abc366 G)

题目大意

给定一张图,给每个点一个点权,使得每个点的邻居的点权异或和为0。给出方案,或告知不能。

解题思路

<++>

神奇的代码


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/18352899

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(677)  评论(0编辑  收藏  举报
历史上的今天:
2020-08-10 2020百度之星程序设计大赛复赛
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.