# [题解] 2023 杭电多校 Rikka with Square Numbers [数论]
哎,数学!
# 题目大意
每次操作可以加或者减一个完全平方数,问至少多少次可以把 变成。
。
# 题解
看到这个题面首先想了 或者搜索的做法。
发现这里的加减两个方向的转移其实没办法很好地。而且并没有找到合理的操作策略,不像是直接能递推出来的。
所以大概率是个结论题。然而我对数学不那么敏感,也推不出来什么式子。
如果当初先暴力打个表说不定就有思路了,那就能看到答案其实只有 或 或。
那么我们就分类讨论。为了方便这里不妨令,反正操作可逆,做等价交换。
- 答案是 的情况:即 是一个完全平方数。
- 答案是 的情况: 不是完全平方数,但是可以由两个完全平方数或加或减凑出来。令:
- 如果是两个平方数相加得到,令,这时候通过枚举即可在 时间内判断。
- 如果是两个平方数相减得到,令,不妨令。我们有平方差公式。这时再对 和 的奇偶性做一下讨论:
- 和 一奇一偶,那么 显然是奇数。一个奇数 必然可以找到 和 满足 且。也就是说 d 为奇数的情况自然满足操作两步可达。
- 和 双奇或双偶,那么 显然是 的倍数。令,这时令 即可满足。
- 答案不为 或 时,注意到这时 一定为偶数 ( 为奇数一定至少 步可以完成), 那么我们只要先用 步将 减掉, 即可再用 步满足,所以答案为。
至此,所有情况讨论完了。代码主要只有一个判断两平方之和的循环,时间复杂度。
# 代码
#include<cstdio> | |
#include<map> | |
#include<cmath> | |
const int MAXN=1e9; | |
bool isqr(const int &x){ | |
if(x==0) return 0; | |
int t=sqrt(x); | |
return t*t==x; | |
} | |
int main(){ | |
int T; | |
scanf("%d",&T); | |
while(T--){ | |
int a,b; | |
scanf("%d%d",&a,&b); | |
int d=a-b; | |
if(d<0) d=-d; | |
if(d==0) | |
printf("0\n"); | |
else if(isqr(d)) | |
printf("1\n"); | |
else if(d&1 || d%4==0) | |
printf("2\n"); | |
else{ | |
bool fg=0; | |
for(int i=1;i*i<d && !fg;++i) | |
if(isqr(d-i*i)) | |
fg=1; | |
if(fg) | |
printf("2\n"); | |
else | |
printf("3\n"); | |
} | |
} | |
} |