【BZOJ】【2219】数论之神
中国剩余定理+原根+扩展欧几里得+BSGS
题解:http://blog.csdn.net/regina8023/article/details/44863519
新技能get√:
1 LL Get_yuangen(LL p,LL phi){ 2 int c=0; 3 for(int i=2;i*i<=phi;i++) 4 if (phi%i==0) 5 f[++c]=i,f[++c]=phi/i; 6 for(int g=2;;g++){ 7 int j; 8 for(j=1;j<=c;j++) if (Pow(g,f[j],p)==1) break; 9 if (j==c+1) return g; 10 } 11 return 0; 12 }
1 void Split(int x){ 2 num=0; 3 for(int i=2;i*i<=x;i++) 4 if (x%i==0){ 5 a[++num].p=i; 6 a[num].c=0; a[num].pc=1; 7 while(x%i==0) 8 x/=i,a[num].c++,a[num].pc*=i; 9 if (x==1) break; 10 } 11 if (x!=1) 12 a[++num].p=x,a[num].pc=x,a[num].c=1; 13 }
1 /************************************************************** 2 Problem: 2219 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:288 ms 7 Memory:5076 kb 8 ****************************************************************/ 9 10 //BZOJ 2219 11 #include<cmath> 12 #include<map> 13 #include<cstdio> 14 #include<cstring> 15 #include<cstdlib> 16 #include<iostream> 17 #include<algorithm> 18 #define rep(i,n) for(int i=0;i<n;++i) 19 #define F(i,j,n) for(int i=j;i<=n;++i) 20 #define D(i,j,n) for(int i=j;i>=n;--i) 21 #define pb push_back 22 using namespace std; 23 typedef long long LL; 24 inline int getint(){ 25 int r=1,v=0; char ch=getchar(); 26 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 27 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 28 return r*v; 29 } 30 const int N=1e5+10; 31 const LL inf=1e18; 32 /*******************template********************/ 33 34 map<LL,LL> mp; 35 struct data{ 36 LL p,c,pc; 37 }a[N]; 38 int num,cnt; 39 LL f[N]; 40 void Split(int x){ 41 num=0; 42 for(int i=2;i*i<=x;i++) 43 if (x%i==0){ 44 a[++num].p=i; 45 a[num].c=0; a[num].pc=1; 46 while(x%i==0) 47 x/=i,a[num].c++,a[num].pc*=i; 48 if (x==1) break; 49 } 50 if (x!=1) 51 a[++num].p=x,a[num].pc=x,a[num].c=1; 52 } 53 LL Pow(LL a,LL b,LL p){ 54 LL r=1; 55 for(;b;b>>=1,a=a*a%p) if (b&1) r=r*a%p; 56 return r; 57 } 58 59 LL Get_yuangen(LL p,LL phi){ 60 int c=0; 61 for(int i=2;i*i<=phi;i++) 62 if (phi%i==0) 63 f[++c]=i,f[++c]=phi/i; 64 for(int g=2;;g++){ 65 int j; 66 for(j=1;j<=c;j++) if (Pow(g,f[j],p)==1) break; 67 if (j==c+1) return g; 68 } 69 return 0; 70 } 71 72 void exgcd(LL a,LL b,LL &d,LL &x,LL &y){ 73 if (!b) {d=a;x=1;y=0;return;} 74 else{exgcd(b,a%b,d,y,x); y-=x*(a/b);} 75 } 76 77 LL BSGS(LL A,LL B,LL C){ 78 int m=ceil(sqrt(C+0.5)); 79 mp.clear(); 80 LL now=1; 81 F(i,1,m){ 82 now = now*A%C; 83 if (!mp[now]) mp[now]=i; 84 } 85 mp[1]=0; 86 A=Pow(A,m,C); 87 now=1LL; 88 F(i,0,m){ 89 LL d,x,y; 90 exgcd(now,C,d,x,y); 91 x=(x*B%C+C)%C; 92 if (mp.count(x)) return i*m+mp[x]; 93 now=now*A%C; 94 } 95 return 0; 96 } 97 98 LL gcd(LL a,LL b){return b ? gcd(b,a%b) : a;} 99 100 LL solve(LL A,LL B,LL k){ 101 LL phi=a[k].pc-a[k].pc/a[k].p, 102 g=Get_yuangen(a[k].pc,phi); 103 LL ind=BSGS(g,B,a[k].pc); 104 LL ans=gcd(phi,A); 105 if (ind%ans) return 0; 106 return ans*Pow(a[k].p,cnt-cnt/A,inf); 107 } 108 109 110 int main(){ 111 #ifndef ONLINE_JUDGE 112 freopen("2219.in","r",stdin); 113 freopen("2219.out","w",stdout); 114 #endif 115 int T=getint(); 116 while(T--){ 117 LL A=getint(),B=getint(),k=getint(); 118 LL p=2*k+1; 119 Split(p); 120 LL ans=1; 121 F(i,1,num){ 122 if (!ans) break; 123 if (B%a[i].pc==0) 124 ans=ans*Pow(a[i].p,a[i].c-(a[i].c-1)/A-1,inf); 125 else{ 126 int b=B; 127 cnt=0; 128 while((b%a[i].p)==0){ 129 b/=a[i].p; 130 a[i].pc/=a[i].p; 131 a[i].c--,cnt++; 132 } 133 if (cnt % A) ans=0; 134 else ans=ans*solve(A,b,i); 135 } 136 } 137 printf("%lld\n",ans); 138 } 139 return 0; 140 }
2219: 数论之神
Time Limit: 3 Sec Memory Limit: 259 MBSubmit: 410 Solved: 48
[Submit][Status][Discuss]
Description
在 ACM_DIY群中,有一位叫做“傻崽”的同学由于在数论方面造诣很高,被称为数轮之神!对于任何数论问题,他都能瞬间秒杀!一天他在群里面问了一个神 题: 对于给定的3个非负整数 A,B,K 求出满足 (1) X^A = B(mod 2*K + 1) (2) X 在范围[0, 2K] 内的X的个数!自然数论之神是可以瞬间秒杀此题的,那么你呢?
Input
第一行有一个正整数T,表示接下来的数据的组数( T <= 1000) 之后对于每组数据,给出了3个整数A,B,K (1 <= A, B <= 10^9, 1 <= K <= 5 * 10^8)
Output
输出一行,表示答案
Sample Input
3
213 46290770 80175784
3 46290770 80175784
3333 46290770 80175784
213 46290770 80175784
3 46290770 80175784
3333 46290770 80175784
Sample Output
27
27
297
27
297
HINT
新加数组一组--2015.02.27