結果
| 問題 |
No.981 一般冪乗根
|
| ユーザー |
|
| 提出日時 | 2021-01-26 14:04:46 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,882 ms / 6,000 ms |
| コード長 | 5,832 bytes |
| コンパイル時間 | 1,195 ms |
| コンパイル使用メモリ | 87,136 KB |
| 実行使用メモリ | 66,896 KB |
| 最終ジャッジ日時 | 2024-06-23 13:45:20 |
| 合計ジャッジ時間 | 83,818 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 36 RE * 4 TLE * 4 |
ソースコード
//#define TEST
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
const int M=1e7+10;
bool is_p[M];
int prime[M], primelen;
int euler(int N) {
int len = 0;
memset(is_p, true, sizeof(is_p));
for(int i = 2; i < N; i++) {
if(is_p[i]) {
prime[len] = i;
len++;
}
for(int j = 0; j < len && prime[j] <= i; j++) {
if(i * prime[j] >= N) break;
is_p[i * prime[j]] = false;
if(i % prime[j] == 0) break;
}
}
return len;
}
LL qmul(LL a,LL b,LL mod){
return (LL)((__int128_t)a*b%mod);
/*
LL ans=0;
while(b>0)
{
if(b&1) ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
*/
}
LL qpow(LL a, LL b, LL mod){
if(b==0)return 1ll;
LL ans=1;
while(b>0){
if(b&1)ans=qmul(ans,a,mod);
a=qmul(a,a,mod);
b>>=1;
}
return ans;
}
LL gcd(LL a,LL b){
while(b){
LL t=a%b;
a=b;
b=t;
}
return a;
}
LL exgcd(LL a,LL b,LL &x,LL &y){
if(b == 0){
x = 1, y = 0;
return b;
}
LL d = exgcd(b, a%b, x, y);
LL t = y;
y = x - y * (a / b);
x = t;
return d;
}
LL solveLinear(LL a,LL b,LL p){
a=(a%p+p)%p;b=(b%p+p)%p;
LL x,y;
LL d=exgcd(a,p,x,y);
if(b%d!=0) return -1;
return (qmul(b/d,x,p/d)+p/d)%(p/d);
}
LL invP(LL a,LL p){
a=(a%p+p)%p;
if(a==0) return -1;
LL x,y;
exgcd(a,p,x,y);
return (x%p+p)%p;
}
int factorlist(LL x,LL z,LL* p,int* k){
int cnt=0;
LL y=gcd(z/x,x);
LL cap=pow(z,0.25)+1;
for(int i=0;prime[i]<=cap;i++){
if(y%prime[i]!=0) continue;
cnt++;
p[cnt]=prime[i];
while(y%prime[i]==0){
y/=prime[i];
}
}
if(y>1){
cnt++;
p[cnt]=y;
}
for(int i=1;i<=cnt;i++){
k[i]=0;
while(x%p[i]==0){
x/=p[i];
k[i]++;
}
}
p[0]=x;
return cnt;
}
const LL hashmod=1000003;
LL phash[hashmod+1000];
LL r_origin[hashmod+1000];
LL bsgs(LL a, LL b, LL p){//计算使得a^k=b modp的最小k
if(a % p == b % p) return 1;
if(a % p == 0 && b % p != 0) return -1;
if(b % p == 1) return 0;
LL m = (LL)ceil(sqrt(p));
a = (a%p+p)%p;
LL r = (b%p+p)%p;
memset(phash,-1,sizeof(phash));
memset(r_origin,-1,sizeof(r_origin));
LL k;
phash[r%hashmod] = 0;//建立hash
r_origin[r%hashmod]=r;
for(LL j = 1; j < m; j++){//baby step
r = qmul(r, a, p);
k=r%hashmod;
while(phash[k]!=-1) k++;
phash[k] = j;
r_origin[k]=r;
}
LL am = qpow(a, m ,p);//快速幂计算a^m
LL t = 1;
for(LL i = 1; i <= m; i++){//giant step
t = qmul(t, am, p);
k=t%hashmod;
if(phash[k]!=-1){
while(phash[k]!=-1){
if(r_origin[k]==t) return m * i - phash[k];
k++;
}
}
}
return -1;
}
LL tonelli(LL P,LL p,int k,LL A,LL invA){
LL n=1;
for(int i=0;i<k;i++) n*=p;
if(qpow(A,(P-1)/n,P)!=1) return -1;
LL v,d,q=P-1;
int s=0;
while(q%p==0){q/=p;s++;}
exgcd(n,q,v,d);
v=(v%q+q)%q;
#ifdef TEST
printf("n=%lld q=%lld p=%lld s=%d k=%d v=%lld\n",n,q,p,s,k,v);
#endif
LL X=qpow(A,v,P);
int t=k+1;
LL B=2;
while(qpow(B,(P-1)/p,P)==1) B++;
#ifdef TEST
printf("W=%lld\n",B);
#endif
B=qpow(B,q,P);
LL invB=invP(B,P);
#ifdef TEST
printf("B=%lld B^-1=%lld\n",B,invB);
#endif
LL E=X;
for(int i=1;i<=k;i++) E=qpow(E,p,P);
E=qmul(E,invA,P);
#ifdef TEST
printf("X=%lld E=%lld\n",X,E);
#endif
while(E!=1){
LL Bps=B,Eps=E;
for(int i=1;i<=s-1;i++) Bps=qpow(Bps,p,P);
for(int i=1;i<=s-t;i++) Eps=qpow(Eps,p,P);
#ifdef TEST
printf("t=%d Bps=%lld Eps=%lld\n",t,Bps,Eps);
#endif
LL r=bsgs(Bps,Eps,P);
Bps=qpow(invB,r,P);
#ifdef TEST
printf("r=%lld\n",r);
#endif
for(int i=0;i<=t-1;i++){
if(i==t-k-1) X=qmul(X,Bps,P);
if(i==t-1) E=qmul(E,Bps,P);
Bps=qpow(Bps,p,P);
}
#ifdef TEST
printf("X=%lld E=%lld\n",X,E);
#endif
t++;
}
return X;
}
LL work(LL P,LL n,LL A){
A=(A%P+P)%P;
LL g=gcd(n,P-1);
if(qpow(A,(P-1)/g,P)!=1) return -1;
LL inv=invP(n/g,(P-1)/g);
A=qpow(A,inv,P);
LL p[1000],X1,X2,n1,n2;int k[1000];
LL invA=invP(A,P);
#ifdef TEST
printf("P=%lld n=%lld g=%lld A=%lld invA=%lld\n",P,n,g,A,invA);
#endif
int cnt=factorlist(g,P-1,p,k);
#ifdef TEST
printf("p:");for(int i=0;i<=cnt;i++)printf(" %lld",p[i]);printf("\n");
printf("k:");for(int i=0;i<=cnt;i++)printf(" %d",k[i]);printf("\n");
#endif
n1=p[0];
LL v=invP(n1,(P-1)/n1);
X1=qpow(A,v,P);
for(int i=1;i<=cnt;i++){
#ifdef TEST
printf("------------------------\n");
#endif
X2=tonelli(P,p[i],k[i],A,invA);
if(X2==-1) return -1;
n2=1;
for(int j=1;j<=k[i];j++) n2*=p[i];
#ifdef TEST
printf("n1=%lld X1=%lld n2=%lld X2=%lld\n",n1,X1,n2,X2);
#endif
LL alpha,beta;
exgcd(n1,n2,alpha,beta);
if(alpha<=0){
X1=qpow(X1,beta,P);
X2=qpow(invP(X2,P),-alpha,P);
}
else if(beta<=0){
X1=qpow(invP(X1,P),-beta,P);
X2=qpow(X2,alpha,P);
}
X1=qmul(X1,X2,P);
n1*=n2;
}
return X1;
}
int main(){
primelen=euler(M);
int T;
scanf("%d",&T);
for(;T>0;T--){
LL P,n,A,X;
scanf("%lld%lld%lld",&P,&n,&A);
X=work(P,n,A);
printf("%lld\n",X);
}
return 0;
}