Atcoder方向
Luogu方向
考虑等式两边都为多次齐次项
令等式左边的值为 F ( x , y , z ) F(x,y,z) F(x,y,z),等式右边的值为 G ( x , y , z ) G(x,y,z) G(x,y,z)
当 F ( x , y , z ) ≡ t ∗ G ( x , y , z ) ( m o d p ) F(x,y,z)\equiv t*G(x,y,z)\;(mod \;p) F(x,y,z)≡t∗G(x,y,z)(modp)
因为等式左边比等式右边高一次
所以 F ( x t , y t , z t ) ≡ G ( x t , y t , z t ) ( m o d p ) F(\frac{x}{t},\frac{y}{t},\frac{z}{t})\equiv G(\frac{x}{t},\frac{y}{t},\frac{z}{t})\;(mod\;p) F(tx,ty,tz)≡G(tx,ty,tz)(modp)
由式子可以 t = F ( x , y , z ) ∗ G ( x , y , z ) − 1 t=F(x,y,z)*G(x,y,z)^{-1} t=F(x,y,z)∗G(x,y,z)−1
因为 t ≠ 0 t\ne 0 t=0,所以 F ( x , y , z ) F(x,y,z) F(x,y,z) 与 G ( x , y , z ) G(x,y,z) G(x,y,z) 不等于 0 0 0,就一定有一组解
考虑没有解的情况出现概率较小( < 1 4 <\frac{1}{4} <41),所以考虑随机 x , y , z x,y,z x,y,z 的值,直到找到一组合法的解
#include
#define int long long
using namespace std;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int qmi(int a,int b,int p){
int res=1;
for(;b;b>>=1){
if(b&1) res=res*a%p;
a=a*a%p;
}
return res;
}
void work(){
int n=read(),p=read();
while(true){
int x=rand()%(p-1)+1,y=rand()%(p-1)+1,z=rand()%(p-1)+1;
if(x==y||x==z||y==z) continue;
int xn=qmi(x,n,p),yn=qmi(y,n,p),zn=qmi(z,n,p);
int mi0=(x+y+z)%p,mi1=(xn+yn+zn)%p,mi2=(xn*xn%p+yn*yn%p+zn*zn%p)%p;
int Left=mi0*mi1%p*mi2%p,Right=(xn*xn%p*xn%p+yn*yn%p*yn%p+zn*zn%p*zn%p)%p;
// cout<
if(!Right||!Left) continue;
int t=Right*qmi(Left,p-2,p)%p;
x=x*t%p,y=y*t%p,z=z*t%p;
// cout<
if(x>y) swap(x,y);
if(x>z) swap(x,z);
if(y>z) swap(y,z);
printf("%lld %lld %lld\n",x,y,z);
return;
}
}
signed main(){
srand(time(NULL));
int T=read();
while(T--) work();
return 0;
}