前言
这道题您看上去难道不是广搜题吗 ? 数学题的标签是来迷惑人的?(貌似我并不知道数学用在哪里了)
思路
首先为什么考虑广度优先搜索?
不难发现这道题目给出的模数相当的小啊,同时我们要求出最少次数。
于是我们用广搜的话,对于每一个余数我们最多遍历一次,于是时间复杂度为:
O( * ) (Mod 表示余数大小)
同时因为广搜的性质,所以会使得Y第一次被遍历到的时候得到的值就是最优解。
说完了大体思路,就来讲一讲细节的地方吧(这道题目细节挺多的)。
坑点1:给出的 X == Y 的时候,应该直接输出 0
坑点2:给出的 X == 0 并且 Y != X 的时候,肯定怎么样也得不到答案,输出-1
坑点3:Y >= Mod 的时候,假若 X != Y , 无解
坑点4(最坑的地方): 考虑到给出的 X 可能会大于 Mod,在广搜第一次进队的时候,不要直接把 X 给入队,先要判断 X 和 Mod 的大小关系,倘若 X >= Mod ,那么我们应该入队的是 F(X) 以及 G(X) , 入 X 的话可能会导致段错误。 如果 X < Mod 就没有什么影响,直接入队即可。
坑点5,因为有模意义下的减法,减的时候注意加上模数的平方(因为后面减的数是 Mod 的平方级别的,这道题好像不加也不会死,但是注意一下吧,养成习惯,
毕竟NOIP连先乘后除都卡)坑点6:注意多取模,因为是 x 的三次方,防止挂掉多取模一下
具体的话可以看一看代码吧,有注释。
Code
#include <bits/stdc++.h> using namespace std; #define int long long const int Mod = 233; int D[500],Y; int F(int x) { return (((x % Mod) * (x % Mod) * (x % Mod)) + (x % Mod) * (x % Mod)) % Mod; //模拟F(x)即可 } int G(int x) { return (((x % Mod) * (x % Mod) * (x % Mod)) + Mod * Mod/*(注意是加上Mod的平方)*/ - (x % Mod) * (x % Mod)) % Mod; //模意义下的减法 } void BFS(int x) { queue <int> q; if(x < Mod)//如果X < Mod 没有影响,入队即可 { q.push(x); D[x] = 0; } else { q.push(F(x)),D[F(x)] = 1;//入队的就是F(X) 和 G(X) q.push(G(x)),D[G(x)] = 1; } while(!q.empty()) { int X = q.front(); q.pop(); if(X == Y) return ;//已经搜索到了答案 if(D[F(X)] == 0ll)q.push(F(X)),D[F(X)]= D[X] + 1;//D[F(x)] == 0 就表示还没有被遍历 if(D[G(X)] == 0ll)q.push(G(X)),D[G(X)] = D[X] + 1; } return ; } signed main() { int T; cin >> T; while(T --) { int x; cin >> x >> Y; if(x == Y){cout << 0 << endl; continue;}//坑点一 if(Y >= 233 || x == 0){cout << -1 << endl; continue ;}// 坑点2,3 memset(D,0ll,sizeof(D)); BFS(x); if(D[Y] != 0ll)//如果最后被遍历到,就有解 cout << D[Y] << endl; else cout << -1 << endl;//否则无解 } return 0; }
总结
总体上来说实现上难度不是很大,但是建议强烈建议读者自己打一打(细节比较多)
是一道搜索 毒瘤 好题