🚀欢迎来到本文🚀
🍉个人简介:陈童学哦,彩笔ACMer一枚。
🏀所属专栏:杭电多校集训
本文用于记录回顾总结解题思路便于加深理解。
不是哥们,怎么我tm什么都不会。
1004 cats 的重力拼图
ProblemDescription
cats 有一个有 n 行,每行有 m 个方格的重力拼图。其中第 i 行第 j 个方格坐标为 (i,j)。重力拼图中有一个物块,初始位于坐标 (a,b) 的方格。若当前物块位于 (r,c),在一次操作中,cats 可以选择以下四种操作之一:
- 将重力切换为向上:将物块从当前位置移动到 (1,c)。这个过程中物块将经过所有坐标为 (i,c) (1≤i≤r) 的方格。
- 将重力切换为向下:将物块从当前位置移动到 (n,c)。这个过程中物块将经过所有坐标为 (i,c) (r≤i≤n) 的方格。
- 将重力切换为向左:将物块从当前位置移动到 (r,1)。这个过程中物块将经过所有坐标为 (r,i) (1≤i≤c) 的方格。
- 将重力切换为向右:将物块从当前位置移动到 (r,m)。这个过程中物块将经过所有坐标为 (r,i) (c≤i≤m) 的方格。
cats 可以最多进行 142857 次操作。现在 cats 希望最大化被拼图块经过至少一次(包括初始位置和最终位置)的方格的总数。你需要告诉 cats 这个总数的最大值。
解题思路
首先我们发现,一个点只能走到该点的左右极限端点和上下极限端点。
我们先考虑极端条件,当现在的点处于四个角落时,那么显然该点的运动轨迹应该为我们矩阵的最外面的那一圈矩形。
一般条件下的点的话我们则需要额外考虑是n大还是m大。
需要注意的是这里求得是格子数,所以计算答案时应该减去2。
最后还有一个特殊情况就是n 或 m 等于1的时候
AC代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 2e5 + 10;
void solve(){
int n,m,a,b;
cin >> n >> m >> a >> b;
int ans = 0;
//特殊情况
if(n == 1 || m == 1){
cout << n * m << "\n";
return;
}
//极端条件下的格子数
ans = (n + m) * 2 - 4;
//如果在四个角落就直接输出
if((a == 1 || a == n) && (b == 1 || b == m)){
cout << ans << "\n";
return;
}
int cnt = 0;
//一般条件下的点的额外贡献
if(a > 1 && a < n){
cnt = max(cnt,m - 2);
}
if(b > 1 && b < m){
cnt = max(cnt,n - 2);
}
cout << ans + cnt << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while(t --){
solve();
}
return 0;
}
1007 cats 的 k-xor
Problem Description
定义两个数 x,y 的 k-xor 为 x,y 在正整数 k (k≥2) 进制意义下的不进位加法。现在 cats 有两个整数 a,b,cats 算出了它们在某个进制 k 下的 k-xor 为 c。但在 cats 计算出 c 后,cats 忘记了 k 的值。你能帮 cats 算出所有大于等于 2 的可能是 k 的不同正整数个数吗?如果有无穷多个满足条件的 k,输出 −1。
注:两个数在 k 进制下的不进位加法为,将两个数分别写出它们的 k 进制表示,并将两个数对应的位分别相加,然后将每一位相加得到的结果分别对 k 取模,将结果看做一个新的 k 进制数,这个结果即为两个数 k 进制下不进位加法的结果。例如 16=(121)3 和 8=(022)3 在 3 进制下的不进位加法的结果即为 (110)3=12。
解题思路
一般这种有特殊情况的,我考虑先判断出什么情况下会造成特殊情况成立。
那么这里很显然当我们的
a
+
b
=
c
a + b = c
a+b=c时会有无穷个k满足条件,因为只要
k
>
c
k > c
k>c即可。
其次当
a
+
b
<
c
a + b < c
a+b<c的时候是没有无解的。因为
a
+
b
a + b
a+b是不进位加法,那么无论
k
k
k为何值
都无法满足
a
+
b
=
c
a + b = c
a+b=c。
最后就是
a
+
b
>
c
a + b > c
a+b>c 时,我们观察到a,b,c的最大值为1e9,开个根号大概50000左右。
2 到 50000 我们直接枚举有多少个k满足条件,大于50000的进制必然只有一个,大家可以自己
想想。
AC代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 2e5 + 10;
int calc(int a,int b,int k){
vector<int> f;
while(a || b){
int u = a % k;
a /= k;
int v = b % k;
b /= k;
f.push_back((u + v) % k);
}
int sum = 0;
int res = 1;
for(auto x : f){
sum += x * res;
res *= k;
}
return sum;
}
void solve(){
int a,b,c;
cin >> a >> b >> c;
int ans = 0;
//无穷的情况
if(a + b == c){
cout << -1 << "\n";
return;
//0的情况
}else if(a + b < c){
cout << 0 << "\n";
return;
//大于50000的情况
}else if(a + b - c > 50000) {
if(calc(a,b,a + b - c) == c){
ans ++;
}
}
//枚举小范围
for(int i = 2;i <= 50000;i ++){
if(calc(a,b,i) == c){
ans ++;
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while(t --){
solve();
}
return 0;
}