\[借用SDUT版《不是,哥们》镇楼 \]
A、欢迎来到山东理工大学第十六届程序设计竞赛(我是听话的乖宝宝)
分析
分析?没有分析~
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cout << "YES" << "\n";
}
B、Q的网课(模拟)
分析
使用map记录每个网课的上课时间即可
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n;
std::cin >> n;
std::map<std::string, int> mp;
for (int i = 0; i < n; ++i) {
std::string s;
int x;
std::cin >> s >> x;
mp[s] = x;
}
int w, ans = 0;
for (std::cin >> w; w--;) {
std::string s;
std::cin >> s;
mp[s]--;
if (mp[s] == 0) {
ans += 1;
}
}
std::cout << ans << '\n';
}
C、震惊!最好的走位竟然是...(bfs+dp)
分析
可以发现n最多只有100,也就是说来回至多五十步,因此只要维护以起点为中心的100*100方格内的状态,暴力维护即可。
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
#define int long long
constexpr int P = 998244353;
int n, m, X, Y;
std::cin >> n >> m >> X >> Y;
std::string s;
std::cin >> s;
std::set<std::pair<int, int>> st;
for (int i = 0; i < m; ++i) {
int x, y;
std::cin >> x >> y;
st.emplace(x, y);
}
std::map<std::pair<int, int>, int> f;
std::unordered_map<char, std::pair<int, int>> mp{
{'U', std::pair{0, +1}},
{'D', std::pair{0, -1}},
{'L', std::pair{-1, 0}},
{'R', std::pair{+1, 0}}
};
f[{X, Y}] = 1;
for (auto dir : s) {
auto [dx, dy] = mp[dir];
std::map<std::pair<int, int>, int> g = f;
for (auto [pos, cnt] : f) {
auto [x, y] = pos;
if (!st.count({x + dx, y + dy})) {
x += dx, y += dy;
}
g[{x, y}] = (g[{x, y}] + cnt) % P;
}
std::swap(f, g);
}
std::cout << f[{X, Y}] << '\n';
}
D、会编程的老师(双指针)
分析
双指针扫一遍,时间复杂度\(O(nQ)\)
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n, q;
std::cin >> n >> q;
std::string s;
std::cin >> s;
while (q--) {
std::vector<int> c(26);
std::string t;
std::cin >> t;
int ans = 0, l = 0, r = 0;
while (r < n) {
c[s[r] - 'A'] += 1;
while (t.find(s[r]) != std::string::npos && c[s[r] - 'A'] > 1) {
c[s[l] - 'A'] -= 1;
l += 1;
}
bool ok = true;
for (auto x : t) {
ok &= c[x - 'A'] == 1;
}
if (ok) {
ans = std::max(ans, r - l + 1);
}
r += 1;
}
std::cout << ans << "\n";
}
}
E、不是,哥们(质因数分解+计算贡献)
分析
如果\(a_i^2\)能够被\(a_j\)整除,那么\(a_i^2\)必然包含\(a_j\)的所有质因子且对应的必须质因子数大于等于\(a_j\),则对于\(a_i\)必须包含\(a_j\)所有质因子且对应的的质因子数大于等于\(a_j\)的数量整除二向上取整。可以发现\(a_i \leq 10^6\),因此直接枚举每个\(a_j\),对其进行质因数分解求出最小的使得\([x^2|a_j]\)成立的\(x\),枚举所有\(x\)的倍数进行计算,最后将\(a_j\)放入桶中以便统计。
代码实现
#include <bits/stdc++.h>
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
namespace Factorizer {
std::vector<int> primes;
std::vector<int> least;
void sieve(int n) {
std::vector<int> nums;
least.assign(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (least[i] == 0) {
least[i] = i;
nums.push_back(i);
}
int now = 0;
while (now < (int)nums.size()
&& nums[now] <= least[i] && i * nums[now] <= n) {
least[i * nums[now]] = nums[now];
now += 1;
}
}
primes = nums;
}
constexpr bool miller_rabin(long long n) {
if (n <= 1 || (n != 2 && n % 2 == 0)) return false;
for (auto a : {3, 5, 7, 11, 13, 17, 19, 23, 29}) {
if (n % a == 0) return n == a;
}
if (n < 31 * 31) return true;
long long d = n - 1;
while (d % 2 == 0) d /= 2;
constexpr long long bases[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37
};
for (long long a : bases) {
if (n == a) return true;
long long t = d;
long long y = 1 % n;
for (long long _t = t; _t != 0; _t >>= 1) {
if (_t & 1) y = (__int128) y * a % n;
a = (__int128) a * a % n;
}
while (t != n - 1 && y != 1 && y != n - 1) {
y = (__int128) y * y % n;
t <<= 1;
}
if (y != n - 1 && t % 2 == 0) return false;
}
return true;
}
long long pollard_rho(long long n) {
if (n == 1 || miller_rabin(n)) return n;
long long now = 0;
do {
long long t = std::gcd(++now, n), r = t;
if (t != 1 && t != n) return t;
long long g = 1;
do {
t = ((__int128) t * t % n + now) % n;
r = ((__int128) r * r % n + now) % n;
r = ((__int128) r * r % n + now) % n;
} while ((g = std::gcd(abs(t - r), n)) == 1);
if (g != n) return g;
} while (now < n / now);
return 0;
}
std::vector<long long> factor(long long n) {
if (n == 1) return {};
std::vector<long long> g, d;
d.push_back(n);
while (!d.empty()) {
auto v = d.back();
d.pop_back();
auto rho = pollard_rho(v);
if (rho == v) {
g.push_back(rho);
} else {
d.push_back(rho);
d.push_back(v / rho);
}
}
std::sort(g.begin(), g.end());
return g;
}
}
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
#define int long long
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
constexpr int N = 1e6 + 1, M = 1e3 + 1;
std::vector<int> c(N), num(M);
int ans = 0;
for (int i = 0; i < n; ++i) {
std::vector<int> fac = Factorizer::factor(a[i]);
int x = 1;
for (int j = 0; j < size(fac); ++j) {
int k = j + 1;
while (k < (int)size(fac) && fac[k] == fac[j]) {
k += 1;
}
x *= std::pow<int>(fac[j], (k - j + 1) / 2);
j = k - 1;
}
if (x < M) {
ans += num[x];
} else {
for (int j = x; j < N; j += x) {
ans += c[j];
}
}
for (int j = 1; j < M; ++j) if (a[i] % j == 0) {
num[j] += 1;
}
c[a[i]] += 1;
}
std::cout << ans << '\n';
}
F、森林的奥秘(并查集+树的直径)
分析
发现每次建完树每次删边计算森林直径较为麻烦,因此考虑倒着建树的同时维护每个集合的直径最大值。
代码实现
#include <bits/stdc++.h>
using Edge = int;
struct HLD {
int n, times = 0;
std::vector<int> siz, top, dep, fa, in, out, seq;
std::vector<std::vector<Edge>> adj;
HLD(const auto &adj, int root = 1) : n((int)adj.size() - 1), adj(adj) {
siz.resize(n + 1), top.resize(n + 1), dep.resize(n + 1), in.resize(n + 1), out.resize(n + 1), seq.resize(n + 1), fa.resize(n + 1);
dep[root] = 1, top[root] = root;
dfs_siz(root), dfs_hld(root);
}
void dfs_siz(int u) {
if (fa[u] != 0) {
adj[u].erase(std::find(adj[u].begin(), adj[u].end(), fa[u]));
}
siz[u] = 1;
for (auto &v : adj[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs_siz(v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
std::swap(v, adj[u][0]);
}
}
}
void dfs_hld(int u) {
in[u] = ++ times;
seq[in[u]] = u;
for (auto v : adj[u]) {
top[v] = v == adj[u][0] ? top[u] : v;
dfs_hld(v);
}
out[u] = times;
}
int lca(int u, int v) {
while (top[u] != top[v]) {
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[(lca(u, v))]; }
};
struct DSU {
std::vector<int> p, siz;
DSU(int n) : p(n), siz(n, 1) { std::iota(p.begin(), p.end(), 0); }
int leader(int x) {
while (x != p[x]) x = p[x] = p[p[x]];
return x;
}
bool same(int x, int y) { return leader(x) == leader(y); }
bool merge(int x, int y) {
x = leader(x), y = leader(y);
if (x == y) return false;
siz[x] += siz[y], p[y] = x;
return true;
}
int size(int x) { return siz[leader(x)]; }
};
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n;
std::cin >> n;
std::vector<std::pair<int, int>> edges(n - 1);
std::vector<std::vector<int>> g(n + 1);
for (auto &[a, b] : edges) {
std::cin >> a >> b;
g[a].emplace_back(b);
g[b].emplace_back(a);
}
HLD hld(g);
DSU dsu(n + 1);
std::vector<int> ans(n);
std::vector<std::array<int, 2>> f(n + 1);
for (int i = 1; i <= n; ++i) {
f[i] = {i, i};
}
int max = 0;
for (int i = n - 2; i >= 0; --i) {
auto [a, b] = edges[i];
a = dsu.leader(a), b = dsu.leader(b);
assert(a != b);
std::vector<int> p{f[a][0], f[a][1], f[b][0], f[b][1]};
std::array<int, 2> res;
int maxd = -1;
for (int i = 0; i < 4; ++i) {
for (int j = i + 1; j < 4; ++j) {
int dist = hld.dist(p[i], p[j]);
if (dist > maxd) {
res = {p[i], p[j]};
maxd = dist;
}
}
}
max = std::max(max, maxd);
dsu.merge(a, b);
f[dsu.leader(a)] = res;
ans[i] = max;
}
for (int i = 0; i < n; ++i) {
std::cout << ans[i] << "\n";
}
}
G、ArmyL对比法(模拟)
分析
按题意模拟
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n;
std::cin >> n;
std::vector<int> a(n), b(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
for (int i = 0; i < n; ++i) {
std::cin >> b[i];
}
for (int i = 0; i < n; ++i) {
if (a[i] > b[i]) {
std::cout << "WinWinWin!!!" << '\n';
return 0;
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) if (i != j) {
if (a[i] > b[j]) {
std::cout << "HaHa" << '\n';
return 0;
}
}
}
std::cout << "AreYouOK?" << '\n';
}
H、我最喜欢吃饭了(模拟)
分析
Karashi大佬带带,按照读入顺序维护m个上升序列即可,如果有不能插入的则输出Karashi lovelove,否则输出Karashi cblcd
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i], a[i]--;
}
std::vector<int> q(m, -1);
for (int i = 0; i < n; ++i) {
int u = -1;
for (int j = 0; j < m; ++j) {
if (q[j] < a[i] && (u == -1 || q[j] > q[u])) {
u = j;
}
}
if (u == -1) {
std::cout << "Karashi lovelove" << '\n';
return 0;
}
q[u] = a[i];
}
std::cout << "Karashi cblcd" << '\n';
}
I、树上跳棋(LCA+exgcd)
分析
首先选择直接跳到两个点的LCA上面,如果直接跳出了跟节点那么一定无解。然后使用exgcd判断一下是否有解,随后一步一步往上跳判断即可,具体看代码实现。
代码实现1(倍增维护)
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n;
std::cin >> n;
std::vector<std::vector<int>> g(n + 1);
for (int i = 0; i < n - 1; ++i) {
int a, b;
std::cin >> a >> b;
g[a].emplace_back(b);
g[b].emplace_back(a);
}
std::vector<int> d(n + 1, -1);
const int N = std::__lg(n + 1) + 1;
std::vector<std::vector<int>> fa(n + 1, std::vector<int>(N));
d[1] = 1;
auto dfs = [&](auto &&self, int u) ->void {
for (auto v : g[u]) if (d[v] == -1) {
d[v] = d[u] + 1;
fa[v][0] = u;
for (int i = 1; i < N; ++i) {
int bs = fa[v][i - 1];
fa[v][i] = fa[bs][i - 1];
}
self(self, v);
}
};
dfs(dfs, 1);
auto lca = [&](int x, int y) {
if (d[x] < d[y]) std::swap(x, y);
for (int i = N - 1; i >= 0; --i) if (d[fa[x][i]] >= d[y]) {
x = fa[x][i];
}
if (x == y) return x;
for (int i = N - 1; i >= 0; --i) if (fa[x][i] != fa[y][i]) {
x = fa[x][i], y = fa[y][i];
}
return fa[x][0];
};
auto jump = [&](int x, int k) {
int depth = d[x] - k;
for (int i = N - 1; i >= 0; --i) if (d[fa[x][i]] >= depth) {
x = fa[x][i];
}
return x;
};
int q;
for (std::cin >> q; q--;) [&] {
int p1, d1, p2, d2;
std::cin >> p1 >> d1 >> p2 >> d2;
int dep1 = d[p1], dep2 = d[p2];
int root = lca(p1, p2), dep = d[root];
int s1 = (dep1 - dep + d1 - 1) / d1 * d1, s2 = (dep2 - dep + d2 - 1) / d2 * d2;
if (dep1 - s1 <= 0 || dep2 - s2 <= 0) {
std::cout << "-1" << '\n';
} else {
if (abs(dep1 - dep2) % std::gcd(d1, d2) != 0) {
std::cout << "-1" << '\n';
return ;
}
p1 = jump(p1, s1), dep1 -= s1;
p2 = jump(p2, s2), dep2 -= s2;
while (dep1 > 0 && dep2 > 0) {
if (dep1 == dep2) {
std::cout << p1 << "\n";
return ;
}
if (dep1 > dep2) {
s1 = (dep1 - dep2 + d1 - 1) / d1 * d1;
dep1 -= s1;
if (dep1 <= 0) break;
p1 = jump(p1, s1);
} else {
s2 = (dep2 - dep1 + d2 - 1) / d2 * d2;
dep2 -= s2;
if (dep2 <= 0) break;
p2 = jump(p2, s2);
}
}
std::cout << -1 << '\n';
}
} ();
}
代码实现2(树剖维护)
#include <bits/stdc++.h>
using Edge = int;
struct HLD {
int n, times = 0;
std::vector<int> siz, top, dep, fa, in, out, seq;
std::vector<std::vector<Edge>> adj;
HLD(const auto &adj, int root = 1) : n((int)adj.size() - 1), adj(adj) {
siz.resize(n + 1), top.resize(n + 1), dep.resize(n + 1), in.resize(n + 1), out.resize(n + 1), seq.resize(n + 1), fa.resize(n + 1);
dep[root] = 1, top[root] = root;
dfs_siz(root), dfs_hld(root);
}
void dfs_siz(int u) {
if (fa[u] != 0) {
adj[u].erase(std::find(adj[u].begin(), adj[u].end(), fa[u]));
}
siz[u] = 1;
for (auto &v : adj[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs_siz(v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
std::swap(v, adj[u][0]);
}
}
}
void dfs_hld(int u) {
in[u] = ++ times;
seq[in[u]] = u;
for (auto v : adj[u]) {
top[v] = v == adj[u][0] ? top[u] : v;
dfs_hld(v);
}
out[u] = times;
}
int lca(int u, int v) {
while (top[u] != top[v]) {
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
int rooted_lca(int a, int b, int c) { return lca(a, b) ^ lca(b, c) ^ lca(a, c); }
int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[(lca(u, v))]; }
bool in_subtree(int u, int v) { return in[v] <= in[u] && in[u] <= out[v]; }
int jump(int u, int k) {
if (dep[u] < k) return -1;
int d = dep[u] - k;
while (dep[top[u]] - d && u) u = fa[top[u]];
return seq[in[u] - dep[u] + d];
}
};
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n;
std::cin >> n;
std::vector<std::vector<int>> g(n + 1);
for (int i = 1; i < n; ++i) {
int a, b;
std::cin >> a >> b;
g[a].emplace_back(b);
g[b].emplace_back(a);
}
HLD hld(g);
int q;
for (std::cin >> q; q--;) [&] {
int p1, d1, p2, d2;
std::cin >> p1 >> d1 >> p2 >> d2;
int dep1 = hld.dep[p1], dep2 = hld.dep[p2];
int lca = hld.lca(p1, p2), dep = hld.dep[lca];
int s1 = (dep1 - dep + d1 - 1) / d1 * d1, s2 = (dep2 - dep + d2 - 1) / d2 * d2;
if (dep1 - s1 <= 0 || dep2 - s2 <= 0) {
std::cout << "-1" << '\n';
} else {
if (abs(dep1 - dep2) % std::gcd(d1, d2) != 0) {
std::cout << "-1" << '\n';
return ;
}
p1 = hld.jump(p1, s1), dep1 -= s1;
p2 = hld.jump(p2, s2), dep2 -= s2;
while (dep1 > 0 && dep2 > 0) {
if (dep1 == dep2) {
std::cout << p1 << "\n";
return ;
}
if (dep1 > dep2) {
s1 = (dep1 - dep2 + d1 - 1) / d1 * d1;
dep1 -= s1;
if (dep1 <= 0) break;
p1 = hld.jump(p1, s1);
} else {
s2 = (dep2 - dep1 + d2 - 1) / d2 * d2;
dep2 -= s2;
if (dep2 <= 0) break;
p2 = hld.jump(p2, s2);
}
}
std::cout << -1 << '\n';
}
} ();
}
J、这不是RMQ问题捏 : )(不知道拿什么来形容本题)
分析
本场除了K最难的题(bushi,写了两个多小时,愣是没想到答案就是每一列和的最大值QAQ。
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
std::cin >> n >> m;
std::vector<std::vector<int>> a(n, std::vector<int>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
std::cin >> a[i][j];
}
}
int ans = 0;
for (int i = 0; i < m; ++i) {
int sum = 0;
for (int j = 0; j < n; ++j) {
sum += a[j][i];
}
ans = std::max(ans, sum);
}
std::cout << ans << '\n';
}
K、猜猜数?
分析
没有分析,因为没看懂
标签:std,山东理工大学,fa,int,cin,ACM,dep,vector,SDUTACM From: https://www.cnblogs.com/sleeeeeping/p/18189273