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());
}
View Code

 

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));
        }
      }
    }
}
View Code

 

posted @ 2015-07-01 20:51  Rivendell  阅读(466)  评论(0编辑  收藏  举报