前言
这道题您看上去难道不是广搜题吗 ? 数学题的标签是来迷惑人的?(貌似我并不知道数学用在哪里了)
思路
首先为什么考虑广度优先搜索?
不难发现这道题目给出的模数相当的小啊,同时我们要求出最少次数。
于是我们用广搜的话,对于每一个余数我们最多遍历一次,于是时间复杂度为:
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;
} 总结
总体上来说实现上难度不是很大,但是建议强烈建议读者自己打一打(细节比较多)
是一道搜索 毒瘤 好题

京公网安备 11010502036488号