Bzoj2219 数论之神

Time Limit: 3 Sec  Memory Limit: 259 MB
Submit: 954  Solved: 268

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

Sample Output

27
27
297

HINT

 新加数组一组--2015.02.27

Source

 

数学问题  原根 阶 指标 中国剩余定理 脑洞题

吼题

 

学姐的讲解很棒棒 http://blog.csdn.net/regina8023/article/details/44863519

 

模数$P=2*K+1$很大,在这个范围下没什么方法可以有效计算,所以需要优化数据范围。

将P分解质因数,$p_{1}^{a1}+p_{2}^{a2}+p_{3}^{a3}+...$

分别在每个模$ p_{i}^{ai} $ 的意义下计算出答案,将这些答案累乘起来就是最终的答案。(在每个模意义下选出一个解,则构成了一组同余方程,根据中国剩余定理,每组同余方程对应一个唯一解,所以可以用乘法原理统计总答案数)

假设当前我们在处理一个$p^a$

现在需要求$x^a \equiv b (\mod  p^a)$的解个数

分三类情况讨论:

如果$ gcd(p^a,b)==b $,则x是p的某次幂的形式,直接出解

如果$ gcd(p^a,b)==1 $,问题转化为求$A*indx \equiv indb (\mod p^a)$的解的个数 (ind是指标)

根据扩展欧几里得的推论,若$indb \% gcd(A,phi(p^a)) == 0 $,解的个数为 gcd(A,phi(p^a))

如果$ gcd(p^a,b)>1 $,可以通过放缩范围转化成第二类情况。

 

求逆元时候要注意模数不一定是质数,所以要用欧拉定理来求。

  没意识到这个,直接算p-2次幂,WA得飞起。

吐槽一下数据真的弱,我求原根的时候x%pri==0写成x%pri==1,居然过了样例和discuss的hack

隔壁yhx注释掉BSGS直接交发现A了,也就是说数据其实保证有解,根本不用判0……

 

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<map>
  7 #define LL long long
  8 using namespace std;
  9 const int mxn=100010;
 10 int read(){
 11     int x=0,f=1;char ch=getchar();
 12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 14     return x*f;
 15 }
 16 LL ksm(LL a,LL k){
 17     LL res=1;
 18     while(k){
 19         if(k&1)res=res*a;
 20         a=a*a;
 21         k>>=1;
 22     }
 23     return res;
 24 }
 25 LL ksm(LL a,LL k,int p){
 26     LL res=1;a%=p;
 27     while(k){
 28         if(k&1)res=(LL)res*a%p;
 29         a=(LL)a*a%p;
 30         k>>=1;
 31     }
 32     return res;
 33 }
 34 int gcd(int a,int b){return (!b)?a:gcd(b,a%b);}
 35 int exgcd(int a,int b,LL &x,LL &y){
 36     if(!b){ x=1;y=0;return a;}
 37     int tmp=exgcd(b,a%b,x,y);
 38     int c=x;x=y;y=c-a/b*x;
 39     return tmp;
 40 }
 41 //
 42 int P;
 43 int pri[mxn],cnt=0;
 44 int GetG(int p){//求原根
 45     int tmp=p-1;
 46     int m=sqrt(tmp+0.5);
 47     cnt=0;
 48     for(int i=2;i<=m;i++)
 49         if(tmp%i==0){
 50             while(tmp%i==0)tmp/=i;
 51             pri[++cnt]=i;
 52         }
 53     if(tmp>1)pri[++cnt]=tmp;
 54     for(int g=2;g<p;g++){
 55         bool is=1;
 56         for(int i=1;i<=cnt;i++)
 57             if(ksm(g,(p-1)/pri[i],p)==1){is=0;break;}
 58         if(is)return g;
 59     }
 60     return 0;
 61 }
 62 map<int,int>mp;
 63 int BSGS(int a,int b,int p,int pp){
 64     mp.clear();
 65     int m=sqrt(p),i,j;
 66     int tmp=1;
 67     for(i=1;i<=m;i++){
 68         tmp=(LL)tmp*a%p;
 69         if(tmp==b)return i;
 70         if(!mp[tmp])mp[tmp]=i;
 71     }
 72     mp[1]=0;
 73     int res=1,phi;
 74     if(pp==p)phi=p-1;
 75     else phi=p/pp*(pp-1);
 76     for(i=0;i<=p;i+=m){
 77         LL inv=ksm(res,phi-1,p);
 78         inv=inv*b%p;
 79         if(mp[inv])return mp[inv]+i;
 80         res=(LL)res*tmp%p;
 81     }
 82     return 0;
 83 }
 84 int G,A,B,K;
 85 int solve(int p,int t){//p^t
 86     int pr=ksm(p,t),b=B;
 87     b%=pr;
 88     if(!b)return ksm(p,t-((t-1)/A+1));
 89     int c=0;
 90     while(b%p==0)b/=p,c++;
 91     if(c%A)return 0;//无解
 92     //
 93     int tmp=c/A;
 94     t-=c;
 95     int phi=pr-pr/p;
 96     G=GetG(p);
 97     int ind=BSGS(G,b,pr,p);
 98     int d=gcd(A,phi);
 99     if(ind%d)return 0;
100     return d*ksm(p,(A-1)*tmp);
101 }
102 int main(){
103     int i,j;
104     int T=read();
105     while(T--){
106         A=read();B=read();K=read();
107         P=2*K+1;K=P;
108         int m=sqrt(P),c;
109         int ans=1;
110         for(i=2;i<=m;i++){
111             if(!ans)break;
112             if(K%i==0){
113                 c=0;
114                 while(K%i==0)K/=i,c++;
115                 ans*=solve(i,c);
116             }
117         }
118         if(ans && K>1)ans*=solve(K,1);
119         printf("%d\n",ans);
120     }
121     return 0;
122 }

 

posted @ 2017-05-03 22:29  SilverNebula  阅读(706)  评论(2编辑  收藏  举报
AmazingCounters.com