A. Shovels and Swords
波利卡普玩的是一款著名的电脑游戏(名字就不提了)。在这个游戏中,他可以制作两种工具–铲子和剑。制作一把铲子,波利卡普需要花费两根棍子和一颗钻石;制作一把剑,波利卡普需要花费两颗钻石和一根棍子。
每种工具可以卖到正好一颗绿宝石。如果波利卡普有 $a$ 根木棍和 $b$ 颗钻石,他能赚到多少颗绿宝石?
大概思路
按照官方题解说的,答案应该满足以下三个性质:
- $ans \le a$
- $ans \le b$
- $ans \le \frac{a+b}{3}$
被这题硬控半小时,最后没办法乱蒙了一个纸上不知道哪个角落推出来的关系时,然后1A过了
参考代码
void solve() {
int a, b;
std::cin >> a >> b;
if (a > b) std::swap(a, b);
if (a * 2 <= b) {
std::cout << a << "\n";
return;
} else {
int y = (2 * b - a) / 3;
a -= y;
b -= 2 * y;
int ans = y;
ans += std::min(b, a / 2);
std::cout << ans << "\n";
}
}
官方题解:
void solve() {
int a, b;
std::cin >> a >> b;
std::cout << std::min(std::min(a, b), (a + b) / 3) << "\n";
}
B. Shuffle
你有一个全为0的数组,第x个位置为1,进行q次操作,每次操作可在给出的区间内任选两个数,交换它们的位置。问操作结束后共有多少种可能的数组。(两数组不同当且仅当存在一个i,$a_i \ne a_i’$)
大概思路
直接贪心地维护一个区间,每次操作时,判断区间是否相交,若相交则更新所维护的区间的边界。
一开始读错题了,我还以为区间操作顺序可打乱,研究了半小时怎么处理含x的区间并的长度
参考代码
void solve(){
i64 n, x, m;
std::cin >> n >> x >> m;
i64 L = x, R = x;
auto insect = [&](i64 l, i64 r) {
return std::max(R, r) - std::min(L, l) + 1 < (R - L + 1) + (r - l + 1);
};
while (m--) {
i64 l, r;
std::cin >> l >> r;
if (insect(l, r)) {
L = std::min(L, l);
R = std::max(R, r);
}
}
std::cout << R - L + 1 << "\n";
}
C. Palindromic Paths
给你一个01矩阵,让你可能少地修改,使得任意从(1, 1)到(n, m)的转移路径都为回文路径(只能向下或向右走)
大概思路
根据题目和样例,可以靠直觉知道这个矩阵最后的形式应该有某种对称性。
考虑样例给出的合法矩阵:
$\begin{pmatrix} 1 & 0 & 1 & 1 & 1 & 1 & 1\\ 0 & 1 & 1 & 0 & 1 & 1 & 0\\ 1 & 1 & 1 & 1 & 1 & 0 & 1 \end{pmatrix}$
从起点和终点开始推,易知,只要满足如下条件,该矩阵就是一个合法的01矩阵:
$\begin{pmatrix} \color{#ff0000}{1} & \color{#ffaa00}{0} & \color{#ffff00}{1} & \color{#00ff00}{1} & \color{#666666}{1} & \color{#00ff00}{1} & \color{#ffff00}{1}\\ \color{#ffaa00}{0} & \color{#ffff00}{1} & \color{#00ff00}{1} & \color{#666666}{0} & \color{#00ff00}{1} & \color{#ffff00}{1} & \color{#ffaa00}{0}\\ \color{#ffff00}{1} & \color{#00ff00}{1} & \color{#666666}{1} & \color{#00ff00}{1} & \color{#ffff00}{1} & \color{#ffaa00}{0} & \color{#ff0000}{1} \end{pmatrix}$
相同颜色的数必须全部相同(灰色部分不需要管,因为它是路径中心)
$\begin{pmatrix} \color{#ff0000}{1} & \color{#ffaa00}{0} & \color{#ffff00}{1} & \color{#00ff00}{1} & \color{#00ff00}{1} & \color{#ffff00}{1}\\ \color{#ffaa00}{0} & \color{#ffff00}{1} & \color{#00ff00}{1} & \color{#00ff00}{1} & \color{#ffff00}{1} & \color{#ffaa00}{0}\\ \color{#ffff00}{1} & \color{#00ff00}{1} & \color{#00ff00}{1} & \color{#ffff00}{1} & \color{#ffaa00}{0} & \color{#ff0000}{1} \end{pmatrix}$
而这种情况是没有所谓的路径中心的,所以要注意分奇偶特判一下
参考代码
void solve(){
int n, m;
std::cin >> n >> m;
std::vector<std::vector<int>> a(std::min(n, m) + 1, std::vector<int>(std::max(n, m) + 1));
if (n > m) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
std::cin >> a[j][i];
}
}
std::swap(n, m);
} else {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
std::cin >> a[i][j];
}
}
}
int ans = 0;
for (int j = 1; j <= n + (m - 1 - n) / 2 - (n == m); j++) {
int sum = 0, L = 0, R = 0;
for (int i = 1; i <= n && j - i + 1 >= 1; i++) {
sum++;
L += a[i][j - i + 1];
R += a[n - i + 1][m - (j - i + 1) + 1];
}
if (L == R && (L == 0 || L == sum)) {
continue;
} else {
ans += std::min(L + R, 2 * sum - L - R);
}
}
std::cout << ans << "\n";
}
D. Two Divisors
给你n个数,对于每个数$a_i$,找到它的一对约数$d_1 > 1$, $d_2 > 1$,满足$\gcd(d_1 + d_2, a_i) = 1$,如果不存在,输出-1。($2 \le a_i \le 10^7$)
大概思路
超级水题,为什么他放在D题啊,我觉得放B题都没问题的
一眼就看到1e7这个数据范围,没记错的话,我板子里那个筛子的上限就是1e7。
直接分类讨论即可:
- 当 $a_i$ 为质数时,不存在符合题意的约数对。
- 当 $a_i$ 为某个质数的幂时,显然不行,因为这样加出来的gcd必为那个质数。
- 当 $a_i$ 由两个以上的本质不同的质数构成时,显然可以。若 $a_i = \prod p_i^{c_i}$,直接取 $a_i$ 的最小质因数 $p$,以及 $\frac{a_i}{p^{c}} $ 即可。
参考代码
struct Sieve {
std::vector<int> mpf; // minimum prime factor
std::vector<int> prime;
Sieve(int n) : mpf(n) {
for (int i = 2; i < n; i++) {
if (mpf[i] == 0) {
prime.push_back(i);
mpf[i] = i;
}
for (int j = 0; j < prime.size() and i * prime[j] < n; j++) {
mpf[i * prime[j]] = prime[j];
if (prime[j] == mpf[i])
break;
}
}
}
// get all factors
std::vector<int> getDiv(int x) const {
std::vector<int> _div(1, 1);
while (x > 1) {
int d = mpf[x];
int l = 0, r = _div.size();
while (x % d == 0) {
for (int k = l; k < r; k++) {
_div.push_back(_div[k] * d);
}
x /= d;
l = r, r = _div.size();
}
}
return _div;
}
};
Sieve si(1e7 + 1);
void solve(){
//std::cout << "ok";
int n;
std::cin >> n;
std::vector<std::pair<int, int>> ans(n);
for (int i = 0; i < n; i++) {
int x;
std::cin >> x;
if (si.mpf[x] == x) {
ans[i] = {-1, -1};
} else {
int z = si.mpf[x];
while (x != 1 && x % z == 0) {
x /= z;
//std::cout << x << "\n";
}
if (x == 1) {
ans[i] = {-1, -1};
} else {
ans[i] = {z, x};
}
}
}
for (auto &[x, y] : ans) {
std::cout << x << " ";
}
std::cout << "\n";
for (auto &[x, y] : ans) {
std::cout << y << " ";
}
}