2021暑假模拟赛4
A[CF1552A(800)]
本质上是求序列的不动点个数,也就是和最终排好序的序列相同的地方。
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while (T --> 0) { int N; cin >> N; string S; cin >> S; string T(S); sort(T.begin(), T.end()); int Ans = 0; for (int i = 0; i < N; ++i) { if (S[i] != T[i]) { Ans ++; } } cout << Ans << '\n'; } }
B[CF1110C(1500)]
观察一下容易得出如果$A$存在某一位为$0$,那么答案为将所有为$0$的位填满。如果不存在为$0$的位,那么需要从$A$中找一个子集使得子集是$A$的约数,枚举一下约数即可。
#include <bits/stdc++.h> using namespace std; int pre[] = { 1, 1, 5, 1, 21, 1, 85, 73, 341, 89, 1365, 1, 5461, 4681, 21845, 1, 87381, 1, 349525, 299593, 1398101, 178481, 5592405, 1082401}; int main() { int Q; cin >> Q; vector<int> A(Q); for (int i = 0; i < Q; ++i) { cin >> A[i]; } for (int i = 0; i < Q; ++i) { int h = -1; for (int j = 0; j < 30; ++j) { if (A[i] >> j & 1) { h = j; } } int S = 0; for (int j = 0; j < h; ++j) { if (!(A[i] >> j & 1)) { S |= 1 << j; } } int Ans = 0; if (S == 0) { cout << pre[h - 1] << '\n'; } else { Ans = (A[i] | S); cout << (A[i] | S) << '\n'; } } }
C[1025B(1600)]
这个题的做法较多。由于求任意一个解即可,那么最方便的是找一个质因子。先求出所有$lcm(A_i,B_i)$的$gcd$,那么这里面肯定包含一个合法的质因子,于是枚举里面的质因子判断是否合法即可。
#include <bits/stdc++.h> using namespace std; vector<int> GetPrime(int n) { vector<bool> mark(n + 1); vector<int> Prime; for (int i = 2; i <= n; ++i) { if (!mark[i]) { Prime.emplace_back(i); } for (int j = 0; j < Prime.size() && i * Prime[j] <= n; ++j) { mark[i * Prime[j]] = true; if (i % Prime[j] == 0) { break; } } } return Prime; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); vector<int> P = GetPrime(100000); int N; cin >> N; vector<long long> A(N); vector<long long> B(N); for (int i = 0; i < N; ++i) { cin >> A[i] >> B[i]; } long long g = 0; for (int i = 0; i < N; ++i) { long long C = A[i] / __gcd(A[i], B[i]) * B[i]; g = __gcd(g, C); } for (int i : P) { if (g % i == 0) { cout << i << '\n'; exit(0); } } vector<long long> ALL; for (auto i : A) { ALL.push_back(i); } for (auto i : B) { ALL.push_back(i); } for (auto i : ALL) { if (__gcd(i, g) >= 2) { cout << __gcd(i, g) << '\n'; exit(0); } } cout << -1 << '\n'; }
D[CF1517D(1800)]
先观察出几个有用的性质:
1.去的路和返回的路肯定是一样的,否则不优
2.$k$必须为偶数,否则无法返回
由这两个性质可以把题目转化为求从任意一个点出发走$\frac{k}{2}$步的最远距离。考虑$dp[i][j][k]$表示走了$k$步,走到了$(i,j)$,转移枚举相邻的点走下一步即可。
#include <bits/stdc++.h> using namespace std; const long long Inf = numeric_limits<long long> :: max() / 3; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, M, K; cin >> N >> M >> K; vector<vector<int>> A(N, vector<int> (M)); for (int i = 0; i < N; ++i) { for (int j = 0; j < M - 1; ++j) { cin >> A[i][j]; } } vector<vector<int>> B(N, vector<int> (M)); for (int i = 0; i < N - 1; ++i) { for (int j = 0; j < M; ++j) { cin >> B[i][j]; } } if (K % 2 == 1) { for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { cout << -1 << " \n"[j == M - 1]; } } exit(0); } vector<vector<pair<int, int>>> adj(N * M); auto id = [&] (int X, int Y) -> int { return X * M + Y; }; for (int i = 0; i < N; ++i) { for (int j = 0; j < M - 1; ++j) { adj[id(i, j)].emplace_back(id(i, j + 1), A[i][j]); adj[id(i, j + 1)].emplace_back(id(i, j), A[i][j]); } } for (int i = 0; i < N - 1; ++i) { for (int j = 0; j < M; ++j) { adj[id(i, j)].emplace_back(id(i + 1, j), B[i][j]); adj[id(i + 1, j)].emplace_back(id(i, j), B[i][j]); } } vector<vector<vector<long long>>> dp(N, vector<vector<long long>> (M, vector<long long> (K + 1, Inf))); for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { dp[i][j][0] = 0; } } for (int k = 0; k < K / 2; ++k) { for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { int X = id(i, j); for (auto [Y, W] : adj[X]) { int ii = Y / M; int jj = Y % M; dp[ii][jj][k + 1] = min(dp[ii][jj][k +1], dp[i][j][k] + W); } } } } for (int i = 0; i < N; ++i) { for (int j = 0; j < M; ++j) { cout << (dp[i][j][K / 2] == Inf ? -1 : dp[i][j][K / 2] * 2) << " \n"[j == M - 1]; } } }
相信通过这几场比赛,大家肯定已经熟练掌握位运算以及分解质因数的操作了!