BSGS
求解a^x=b(mod p),p为质数时,直接bsgs就可以了。
将x写作km-j,m=sprt(p)时复杂度最优,a^(km)=ba^j(mod p),我们预先求出a^j(j=0~m-1)存入map,然后穷举k=1~p/m,如果map中有值,返回km-cnt[]就可以了。
bzoj4128 Matrix
题目大意:a^x=b(mod p),a、b为矩阵。
思路:bsgs直接求就可以了,因为不需要求逆,所以方便许多。(注意map要重定义比较符号)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<cmath> using namespace std; struct use{ int num[100][100]; void init() { int i,j; for (i=0;i<100;++i) for (j=0;j<100;++j) num[i][j]=1; } bool operator == (const use & a)const { int i,j; for (i=0;i<100;++i) for (j=1;j<100;++j) if (num[i][j]!=a.num[i][j]) return false; return true; } bool operator < (const use & a)const { int i,j; for (i=0;i<100;++i) for (j=0;j<100;++j) { if (num[i][j]<a.num[i][j]) return true; if (num[i][j]>a.num[i][j]) return false; } return false; } bool operator > (const use & a)const { int i,j; for (i=0;i<100;++i) for (j=0;j<100;++j) { if (num[i][j]>a.num[i][j]) return true; if (num[i][j]<a.num[i][j]) return false; } return false; } }a,b; map <use,int> cnt; int n,p; use calc(use m1,use m2) { int i,j,k; use m3; for (i=1;i<=n;++i) for (j=1;j<=n;++j) { m3.num[i][j]=0; for (k=1;k<=n;++k) m3.num[i][j]=(m3.num[i][j]+(m1.num[i][k]*m2.num[k][j])%p)%p; } return m3; } int bsgs() { use m1,m2; int i,j,m; m1=b;m=sqrt(p);cnt[m1]=1; for (i=1;i<m;++i) { m1=calc(m1,a);cnt[m1]=i+1; } m1=a;for (i=2;i<=m;++i) m1=calc(m1,a); m2=m1; for (i=1;i<=p/m;++i) { if (cnt[m2]!=0) return i*m-cnt[m2]+1; m2=calc(m1,m2); } return 0; } int main() { int i,j; scanf("%d%d",&n,&p); for (i=1;i<=n;++i) for (j=1;j<=n;++j) scanf("%d",&a.num[i][j]); for (i=1;i<=n;++i) for (j=1;j<=n;++j) scanf("%d",&b.num[i][j]); printf("%d\n",bsgs()); }
bzoj3122 随机数生成器
题目大意:ci=(a * ci-1 + b) %p,ci=t的最小i值,如果没有输出-1。
思路:求出ci的通项公式,ci=(a^(ans-1)x1+a^(ans-2)b+...+a^0b)%p=(x1+b/(a-1))*a^(n-1)-b/(a-1),发现,如果a!=0&&a!=1,那么就是bsgs了;如果a=0,就要判断b能否%p=t,如果可以,就是2天,否则-1;如果a=1,就是拓展欧几里德了,但是要注意=t,而不是=1,所以答案是t/d*x%p(注意%p,还有之前求出来的x可能为负,也要转化)。如果答案是0就输出p。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<cmath> #define LL long long using namespace std; LL p; map<LL,int> cnt; void gcd(LL a,LL b,LL &d,LL &x,LL &y){ if (!b){d=a;x=1LL;y=0LL;return;} else{gcd(b,a%b,d,y,x);y-=a/b*x;} } LL mi(LL x,LL y){ if (y==0) return 1LL; if (y==1) return x%p; LL mm=mi(x,y/2); if (y%2) return mm*mm%p*x%p; else return mm*mm%p; } LL calc(LL a,LL b,LL p){ LL i,e=1LL,v,m=(LL)sqrt(p+0.5); cnt.clear(); for (i=1;i<=m;++i){ e=e*a%p;cnt[e*b%p]=i; }for (v=e,i=1;i<=p/m;++i){ if (cnt.count(v)) return i*m-cnt[v]; v=v*e%p; }return -2; } int main(){ int ti;LL j,a,b,x1,t,d,x,y;scanf("%d",&ti); while(ti--){ scanf("%I64d%I64d%I64d%I64d%I64d",&p,&a,&b,&x1,&t); x1%=p;t%=p; if (t==x1){printf("1\n");continue;} if (a==1){ t=(t-x1+b+p)%p;gcd(b,p,d,x,y);x=(x%p+p)%p; if (t%d) printf("-1\n"); else printf("%I64d\n",(t=t/d*x%p)==0?p:t); }else{ if (a==0){ if (b%p==t) printf("2\n"); else printf("-1\n"); }else{ j=mi((a-1LL+p)%p,p-2); x=(x1+b*j%p)%p;y=(t+b*j%p)%p*mi(x,p-2)%p; x=calc(a,y,p); printf("%I64d\n",(x+1==0?p:x+1)); } } } }