【zoj3254】Secret Code

题意:

给出a、p、d、m 求a^x=d(mod p) 0<=x<=m 的解的个数

题解:

今天一整天的时间大部分都在调这题Orz BSGS什么的还是太不熟了

 

我们可以用BSGS拓展版求出最小解x 以及循环节开始的位置start start就是p被除(a,p)的次数

如果不存在解x 或x>m则输出0

如果x<start 那么输出1 因为如果解在循环节之前 在循环节中就不可能有x的解

如果start<=x<=m 答案就是x循环出现的次数=(m-x)/lon (lon是循环节长度)

 

这有些地方要注意的

因为题目的m<=2^63-1 而0<=x<=m 所以可能导致答案爆long long 要开unsigned long long

还有该mod的地方要mod啊 因为一个mod 我段异常了一个早上

然后因为对BSGS不熟 WA了一下午TAT 按AK大神的打法重打一遍才过

 

代码:

  1 #include <cstdio>

  2 #include <cstring>

  3 #include <cmath>

  4 typedef long long ll;

  5 typedef unsigned long long ull;

  6 const ll mo=200003,N=20000;

  7 ll a,p,d,m,sum=1,sq,hash[mo],hat[mo],pri[N],save[N],bo[N+1],tot,add;

  8 ll gcd(ll a,ll b){ return b ? gcd(b,a%b) : a; }

  9 ll extgcd(ll &x,ll &y,ll a,ll b){

 10     if (!b){

 11         x=1,y=0;

 12         return a;

 13     }else{

 14         ll res=extgcd(x,y,b,a%b),t=x;

 15         x=y,y=t-a/b*y;

 16         return res;

 17     }

 18 }

 19 void push(ll x,ll y){

 20     ll t=x%mo;

 21     while (hash[t]>=0){

 22         if (hash[t]==x) return;

 23         t=(t+1)%mo;

 24     }

 25     hash[t]=x,hat[t]=y;

 26 }

 27 void makehash(){

 28     for (ll i=0,x=1%p;i<sq;i++,x=x*a%p) push(x,i);

 29 }

 30 ll ha(ll x){

 31     ll t=x%mo;

 32     while (hash[t]>=0){

 33         if (hash[t]==x) return hat[t];

 34         t=(t+1)%mo;

 35     }

 36     return -1;

 37 }

 38 ll mi(ll a,ll b){

 39     ll res=1;

 40     for (;b;b>>=1){

 41         if (b&1) res=res*a%p;

 42         a=a*a%p;

 43     }

 44     return res;

 45 }

 46 ll makex(){

 47     ll x,y,a1,b1=p,res;

 48     for (ll i=0;i<=sq;i++){

 49         a1=mi(a,sq*i)*sum%p;

 50         ll gc=extgcd(x,y,a1,b1),xx=b1/gc;

 51         if (d%gc) continue;

 52         x=(d/gc*x%xx+xx)%xx;

 53         res=ha(x);

 54         if (res>=0 && res<=p)

 55         return i*sq+res+add;

 56     }

 57     return -1;

 58 }

 59 void makepri(){

 60     for (ll i=2;i<=N;i++){

 61         if (!bo[i]) pri[++pri[0]]=i;

 62         for (ll j=1;j<=pri[0] && i*pri[j]<=N;j++){

 63             bo[i*pri[j]]=1;

 64             if (!(i%pri[j])) break;

 65         }

 66     }

 67 }

 68 bool check(ll t){ return mi(a,t)==1; }

 69 void makesave(ll x){

 70     save[0]=0;

 71     for (ll i=1;i<=pri[0] && x>1;++i)

 72     if (!(x%pri[i])){

 73         save[++save[0]]=pri[i];

 74         while (!(x%pri[i])) x/=pri[i];

 75     }

 76     if (x>1) save[++save[0]]=x;

 77 }

 78 ll phi(ll t){

 79     makesave(t);

 80     ll res=t;

 81     for (ll i=1;i<=save[0];i++)

 82     res=res/save[i]*(save[i]-1);

 83     return res;

 84 }

 85 ll makelon(){

 86     ll t=phi(p);

 87     makesave(t);

 88     for (ll i=1;i<=save[0];i++)

 89     while (check(t/save[i]) && !(t%save[i])) t/=save[i];

 90     return t;

 91 }

 92 int bsgs(){

 93     int addx=1,sd=d,sp=p;

 94     for (int gc=gcd(a,p);gc>1;gc=gcd(a,p)){

 95         if (addx==sd) return add++;

 96         if (d%gc) return -1;

 97         addx=addx*a%sp;

 98         d/=gc,p/=gc;

 99         sum=a/gc*sum%p;

100         ++add;

101     }

102     sq=(ll)sqrt(p);

103     a%=p;

104     makehash();

105     return makex();

106 }

107 void work(){

108     ull res=0;

109     add=0,sum=1;

110     memset(hash,-1,sizeof(hash));

111     ll x=bsgs();

112     if (x==-1 || x>m){

113         puts("0");

114         return ;

115     }else if (x<add){

116         puts("1");

117         return;

118     }

119     ll lon=makelon();

120     res=(m-x)/lon+1;

121     printf("%I64u\n",res);

122 } 

123 int main(){

124     makepri();

125     while (scanf("%I64d%I64d%I64d%I64d",&a,&p,&d,&m)!=EOF){

126         ++tot;

127         //printf("%d:",tot);

128         a%=p;

129         work();

130     }

131 }
View Code

你可能感兴趣的:(code)