【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

posted @ 2013-10-18 23:55  g_word  阅读(274)  评论(0编辑  收藏  举报