AtCoder Beginner Contest 327(A~F)题解 abc327

AtCoder Beginner Contest 327

A - ab

就是看子串中是否包含abba

时间复杂度 O ( N ) O(N) O(N)

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;
	
	std::string s;
	std::cin >> s;

	if (s.find("ab") != std::string::npos || s.find("ba") != std::string::npos) {
		std::cout << "Yes\n";
	} else {
		std::cout << "No\n";
	}

	return 0;
}
B - A^A

虽然 B B B很大,但左式增长速度也非常快,手玩一下当 A = = 16 A == 16 A==16时就会超出 B B B的最大范围,注意这里使用std::pow函数会产生精度问题,所以要自己手写一个幂函数。

时间复杂度 O ( 1 ) O(1) O(1)

#include <bits/stdc++.h>

using i64 = long long;

i64 power(i64 a, int b) {
	i64 res = 1;
	for (; b; b /= 2, a = a * a) {
		if (b % 2) {
			res *= a;
		}
	}
	return res;
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	i64 B;
	std::cin >> B;

	for (i64 x = 1; x <= 15; x++) {
		i64 y = power(x, x);
		if (y == B) {
			std::cout << x << "\n";
			return 0;
		}
	}

	std::cout << "-1\n";
	return 0;
}
C - Number Place

实际上就是按题意模拟一下是否满足数独,考察代码能力

时间复杂度 O ( n 2 ) O(n^{2}) O(n2)

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	const int n = 9;
	std::array<std::array<int, n>, n> a;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			std::cin >> a[i][j];
		}
	}

	bool ok = true;
	for (int i = 0; i < n; i++) {
		std::set<int> f;
		for (int j = 0; j < n; j++) {
			f.emplace(a[i][j]);
		}
		ok &= int(f.size()) == 9;

	}
	for (int j = 0; j < n; j++) {
		std::set<int> f;
		for (int i = 0; i < n; i++) {
			f.emplace(a[i][j]);
		}
		ok &= int(f.size()) == 9;
	}

	for (int i = 0; i < n; i += 3) {
		for (int j = 0; j < n; j += 3) {
			std::set<int> f;
			for (int x = i; x < i + 3; x++) {
				for (int y = j; y < j + 3; y++) {
					f.emplace(a[x][y]);
				}
			}
			ok &= int(f.size()) == 9;
		}
	}

	if (ok) {
		std::cout << "Yes\n";
	} else {
		std::cout << "No\n";
	}
	
	return 0;
}
D - Good Tuple Problem

种类并查集/染色法模板题

时间复杂度 O ( M ) O(M) O(M)

种类并查集:

#include <bits/stdc++.h>

using i64 = long long;
struct DSU {
	int n;
	std::vector<int> f, siz;
	DSU() {}
	DSU(int n) {
		f.resize(n);
		std::iota(f.begin(), f.end(), 0);
		siz.assign(n, 1);
	}

	int find(int x) {
		while (x != f[x]) {
			x = f[x] = f[f[x]];
		}
		return x;
	}

	bool same(int x, int y) {
		x = find(x);
		y = find(y);
		return x == y;
	}

	bool merge(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y) {
			return false;
		}

		siz[x] += siz[y];
		f[y] = x;
		return true;
	}

	int size(int x) {
		return siz[find(x)];
	}
};
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int N, M;
	std::cin >> N >> M;

	std::vector<int> A(M), B(M);
	for (int i = 0; i < M; i++) {
		std::cin >> A[i];
		A[i]--;
	}
	for (int i = 0; i < M; i++) {
		std::cin >> B[i];
		B[i]--;
	}

	DSU dsu(2 * N);
	for (int i = 0; i < M; i++) {
		if (dsu.same(A[i], B[i]) || dsu.same(A[i] + N, B[i] + N)) {
			std::cout << "No\n";
			return 0;
		}
		dsu.merge(A[i], B[i] + N);
		dsu.merge(A[i] + N, B[i]);
	}

	std::cout << "Yes\n";
	return 0;
}

染色法:

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int N, M;
	std::cin >> N >> M;

	std::vector<int> A(M), B(M);
	for (int i = 0; i < M; i++) {
		std::cin >> A[i];
		A[i]--;
	}
	for (int i = 0; i < M; i++) {
		std::cin >> B[i];
		B[i]--;
	}

	std::vector<std::vector<int>> adj(N);
	for (int i = 0; i < M; i++) {
		adj[A[i]].push_back(B[i]);
		adj[B[i]].push_back(A[i]);
	}

	std::vector<int> C(N, -1);
	for (int i = 0; i < N; i++) {
		if (C[i] == -1) {
			C[i] = 0;
			std::queue<int> q;
			q.push(i);

			while (!q.empty()) {
				int x = q.front();
				q.pop();

				for (auto y : adj[x]) {
					if (C[y] == -1) {
						C[y] = C[x] ^ 1;
						q.push(y);
					} else if (C[y] == C[x]) {
						std::cout << "No\n";
						return 0;
					}
				}
			}
		}
	}

	std::cout << "Yes\n";

	return 0;
}
E - Maximize Rating

最开始考虑了贪心策略,但实际上是错误的。

3
800 1200 801

所以就要考虑DP

观察式子的结构会发现其实除了左式的分子,其他部分相对来说都是比较固定的。

dp[i][j]为前i个数选择j个数时分子的最大值,然后就类似于一个背包问题。

状态转移方程为:dp[i][j] = std::max({dp[i][j], dp[i - 1][j], dp[i - 1][j - 1] * 0.9 + P[i]})

最后枚举一下取最大值就好了

时间复杂度 O ( N 2 ) O(N^{2}) O(N2)

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N;
    std::cin >> N;

    std::vector<int> P(N + 1);
    for (int i = 1; i <= N; i++) {
        std::cin >> P[i];
    }

    std::vector dp(N + 1, std::vector<double>(N + 1));
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= i; j++) {
            dp[i][j] = std::max({dp[i][j], dp[i - 1][j], dp[i - 1][j - 1] * .9 + P[i]});
        }
    }

    double ans = -INFINITY;
    double den = 0;
    for (int i = 1; i <= N; i++) {
        den = den * .9 + 1;
        ans = std::max(ans, dp[N][i] / den - 1200 / std::sqrt(i));
    }

    std::cout << std::fixed << std::setprecision(12);
    std::cout << ans << "\n";

    return 0;
}
F - Apples

把题目抽象出来就类似于在一个二维平面内有一些点,然后这个时候要选定一个长宽固定的框,使得这个框内的点数最多。

那么首先可以确定的就是以某一个点作为这个框的左下端点一定包含最优解。

假设以 i i i作为左端点,那么这个框能够覆盖的时间就是 [ X i , X i + D ) [X_i, X_i + D) [Xi,Xi+D),长度就是 [ T i , T i + W ) [T_i, T_i + W) [Ti,Ti+W),所以遇到 X i X_i Xi时我们就给长度区间+1,遇到 X i + D X_i+D Xi+D时就给长度区间-1,答案就是每次取全局最大值。

那么我们就可以枚举时间,以位置建线段树,执行区间加和区间查询的操作。

时间复杂度 O ( N l o g ( 2 E 5 ) ) O(Nlog(2E5)) O(Nlog(2E5))

#include <bits/stdc++.h>

using i64 = long long;

constexpr int inf = 1E9;
struct Tag {
    int add = inf;
    void apply(const Tag& t) {
        if (t.add != inf) {
            if (add == inf) {
                add = 0;
            }
            add += t.add;
        }        
    }
};
 
struct Info {
    int max = 0;
    void apply(const Tag& t) {
        if (t.add != inf) {
            max += t.add;
        }        
    }
};
 
Info operator+(Info a, Info b) {
    Info c;
    c.max = std::max(a.max, b.max);
    return c;
}

constexpr int C = 1 << 18;
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N, D, W;
    std::cin >> N >> D >> W;

    std::vector<std::vector<std::pair<int, int>>> info(C);
    for (int i = 0; i < N; i++) {
        int T, X;
        std::cin >> T >> X;

        info[T].push_back({X, 1});
        if (T + D < C) {
            info[T + D].push_back({X, -1});
        }
    }

    int ans = 0;
    LazySegmentTree<Info, Tag> seg(C);
    for (int x = 0; x < C; x++) {
        for (auto [y, v] : info[x]) {
            seg.rangeApply(y, std::min(C, y + W), {v});
        }

        ans = std::max(ans, seg.rangeQuery(0, C).max);
    }

    std::cout << ans << "\n";

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值