AtCoder Beginner Contest 418
A - I'm a teapot
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
if (n >= 3 && s.substr(n - 3) == "tea") {
std::cout << "Yes\n";
} else {
std::cout << "No\n";
}
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
B - You're a teapot
枚举子串。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
std::string s;
std::cin >> s;
int n = s.size();
auto get = [&](const std::string & s) -> double {
int cnt = std::ranges::count(s, 't');
return (cnt - 2) * 1.0 / ((int)s.size() - 2);
};
double ans = 0;
for (int i = 0; i < n; ++ i) {
for (int j = i + 2; j < n; ++ j) {
if (s[i] == 't' && s[j] == 't') {
ans = std::max(ans, get(s.substr(i, j - i + 1)));
}
}
}
std::cout << std::fixed << std::setprecision(12);
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
C - Flush
题意:第\(i\)个物品有\(a_i\)个,\(q\)次询问,每次给出一个\(b\),你需要求最小的\(x\),使得从所有物品中任意拿\(x\)个都有\(b\)个相同的。
将\(a\)排序,预处理前缀和。
考虑最坏情况,记\(a_j\)为大于等于\(b\)的第一个位置,那么\(\sum_{i=1}^{j-1} a_i\)都选上也不会有\(b\)个相同的。然后大于等于\(j\)的\(a_i\)都选出\(b-1\)个,此时不管再选哪一个都会有一个物品大于等于\(b\)个,所以答案是\(\sum_{i=1}^{j-1} a_i + (n - i + 1) \times (b - 1) + 1\)。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::ranges::sort(a);
std::vector<i64> sum(n + 1);
for (int i = 0; i < n; ++ i) {
sum[i + 1] = sum[i] + a[i];
}
while (q -- ) {
int b;
std::cin >> b;
if (a.back() < b) {
std::cout << -1 << "\n";
} else {
int p = std::ranges::lower_bound(a, b) - a.begin();
i64 ans = sum[p] + (i64)(n - p) * (b - 1) + 1;
std::cout << ans << "\n";
}
}
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
D - XNOR Operation
题意:对于一个\(01\)串,每次可以选择相邻的两个元素,如果相同则用\(1\)替换它们,如果不同则用\(0\)替换它们,最终操作到只剩一个。如果一个\(01\)串可以最后剩下的是\(1\)则这个\(01\)串是好的。求\(s\)有多少子串是好的。
\(01, 10\)会变成\(0\),\(00\)会变成\(1\),发现每次操作\(0\)一定减少偶数个。那么想要最终留下\(1\),整个串里需要有偶数个\(0\)。
记录前缀和的奇偶个数,累加就行。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
int cnt[2]{1, 0};
int sum = 0;
i64 ans = 0;
for (int i = 0; i < n; ++ i) {
sum += s[i] == '0';
ans += cnt[sum & 1];
++ cnt[sum & 1];
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
E - Trapezium
题意:求\(n\)个点里有多少梯形。保证没有三点共线。
把所有边拿出来,按极角排序,那么极角相同的边可以构成梯形。但发现平行四边形会被算两次,于是还需要减去平行四边形的数量。
接下来计算平行四边形个数,这是经典问题,平行四边形两个对角线的中点重合,那么可以用\(map\)记录每个点作为中点的个数,那么从中任意选两个就能组成一个平行四边形。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
using T = i64;
const T inf = 1e18;
const double eps = 0, PI = std::acos(-1);
struct Point {
T x, y;
Point(const T & _x = 0, const T & _y = 0) : x(_x), y(_y) {}
Point operator + (const Point & p) const {
return {x + p.x, y + p.y};
}
Point operator - (const Point & p) const {
return {x - p.x, y - p.y};
}
Point operator * (const T & v) const {
return {x * v, y * v};
}
Point operator / (const T & v) const {
return {x / v, y / v};
}
friend Point operator * (const T & v, const Point & p) {
return p * v;
}
Point & operator += (const Point & p) {
x += p.x;
y += p.y;
return *this;
}
Point & operator -= (const Point & p) {
x -= p.x;
y -= p.y;
return *this;
}
Point & operator *= (const T & v) {
x *= v;
y *= v;
return *this;
}
Point & operator /= (const T & v) {
x /= v;
y /= v;
return *this;
}
Point operator -() const {
return Point(-x, -y);
}
};
//叉乘
T cross(const Point & a, const Point & b) {
return a.x * b.y - a.y * b.x;
}
//分类,极角排序用
int quad(const Point & a) {
if (a.y < -eps) {
return 1;
}
if (a.y > eps) {
return 4;
}
if (a.x < -eps) {
return 5;
}
if (a.x > eps) {
return 3;
}
return 2;
}
//极角排序
struct argcmp {
bool operator()(const Point & a, const Point & b) {
int qa = quad(a), qb = quad(b);
if (qa != qb) {
return qa < qb;
}
auto t = cross(a, b);
//如果相同极角还需要按极径排序
// if (std::fabs(t) <= eps) {
// return dot(a, a) < dot(b, b) - eps;
// }
return t > eps;
}
};
void solve() {
int n;
std::cin >> n;
std::vector<Point> p(n);
for (int i = 0; i < n; ++ i) {
std::cin >> p[i].x >> p[i].y;
p[i] *= 2;
}
std::vector<Point> a;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < n; ++ j) {
if (i != j) {
a.push_back(p[i] - p[j]);
}
}
}
std::sort(a.begin(), a.end(), argcmp());
i64 ans = 0;
for (int i = 0; i < a.size(); ++ i) {
int j = i;
while (j + 1 < a.size() && cross(a[i], a[j + 1]) == 0) {
++ j;
}
i64 t = j - i + 1;
ans += t * (t - 1) / 2;
i = j;
}
ans /= 2;
std::map<std::pair<i64, i64>, int> cnt;
for (int i = 0; i < n; ++ i) {
for (int j = i + 1; j < n; ++ j) {
Point o = (p[i] + p[j]) / 2;
++ cnt[{o.x, o.y}];
}
}
for (auto & [_, c] : cnt) {
ans -= (i64)c * (c - 1) / 2;
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}