• sgu 261


    学习了元根的一些知识,哈哈。

    总结一下:

    几个概念:

    阶:对于模数m和整数a,并且gcd(m,a)==1,那么定义a在模m下的阶r为满足ar=1 mod m的最小正整数。

    性质1:r in [1,phi(m)]   (由欧拉定理)

    性质2:r | phi(m)  ( ar=aphi(m) mod m,然后用反证法)

    性质3:r 是整数a模m的阶当且仅当满足:1)ar=1 mod m   2) a r/p(r) ≠ 1 mod m (后面推前面也用反正法)。

    元根:

    如果对于一个模数m,存在一个数a,满足a在模m下的阶是phi(m),那么就称a是模数m的一个元根。

    性质:所有质数有元根(更一般的,2,4,pe,2pe有元根,p是奇质数)

    元根应用

    元根依靠离散对数,将对数运算引入了模数的缩系下。从而可以解决很多数论中关于指数的问题。

    indga=indgb mod phi(m) <=> a=b mod m

    indgak=k indga mod phi(m)

    indgab=indga+indgb mod phi(m)

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cmath>
      4 #include <vector>
      5 #include <algorithm>
      6 using namespace std;
      7 
      8 typedef long long dnt;
      9 
     10 const int mod = 8543;
     11 const int elen = 100010;
     12 struct Hash {
     13     int head[mod], val[elen], rat[elen], next[elen], etot;
     14     void init() {
     15         memset( head, 0, sizeof(head) );
     16         etot = 0;
     17     }
     18     void insert( int v, int r ) {
     19         int k = v % mod;
     20         etot++;
     21         next[etot] = head[k];
     22         rat[etot] = r;
     23         val[etot] = v;
     24         head[k] = etot;
     25     }
     26     int query( int v ) {
     27         int k = v % mod;
     28         for( int t=head[k]; t; t=next[t] ) 
     29             if( val[t]==v ) return rat[t];
     30         return -1;
     31     }
     32 }hash;
     33 
     34 int p, a, k;
     35 int g, b;
     36 vector<int> stk;
     37 
     38 dnt mpow( dnt a, int b, int m ) {
     39     dnt rt;
     40     for( rt=1; b; b>>=1,a=(a*a)%m )
     41         if( b&1 ) rt=(rt*a)%m;
     42     return rt;
     43 }
     44 void exgcd( int a, int b, int &d, dnt &x, dnt &y ) {
     45     if( b==0 ) d=a, x=1, y=0;
     46     else {
     47         exgcd( b, a%b, d, y, x );
     48         y-=a/b*x;
     49     }
     50 }
     51 int gcd( int a, int b ) {
     52     return b ? gcd(b,a%b) : a;
     53 }
     54 int findroot( int n ) {        //    n is prime
     55     if( n==2 ) return 1;
     56 
     57     vector<int> pfac;
     58     int maxi = (int)ceil(sqrt(n-1));
     59     int remain=n-1;
     60     for( int i=2; i<=maxi; i++ ) {
     61         if( remain%i==0 ) {
     62             pfac.push_back(i);
     63             while( remain%i==0 ) 
     64                 remain/=i;
     65         }
     66     }
     67     if( remain!=1 ) pfac.push_back( remain );
     68     for( int i=1; ; i++ ) {
     69         bool ok = true;
     70         for( int t=0; t<pfac.size(); t++ ) 
     71             if( mpow(i,(n-1)/pfac[t],n)==1 ) {
     72                 ok = false;
     73                    break;
     74             }
     75         if( ok ) return i;
     76     }
     77 }
     78 dnt inv( int a, int n ) {
     79     return mpow(a,n-2,n);
     80 }
     81 dnt ind( int g, int b, int n ) {    //    n is prime, g is root, return v in [0,n-1]
     82     hash.init();
     83     int m = (int)ceil(sqrt(n-1));
     84     dnt s = 1;
     85     for( int i=0; i<m; i++ ) {
     86         if( s==b ) return i;
     87         hash.insert( s, i );
     88         s = (s*g) % n;
     89     }
     90     int am = s;
     91     s = b;
     92     for( int i=m,j; i<n; i+=m ) {
     93         s = (s*inv(am,n)) % n;
     94         if( (j=hash.query(s))!=-1 )
     95             return i+j;
     96     }
     97     return -1;    //    impossible
     98 }
     99 void meq( int a, int b, int m ) {
    100     stk.clear();
    101     int d = gcd(a,m);
    102     if( b%d ) return;
    103     int aa=a/d, bb=b/d, mm=m/d, dd;
    104     dnt x0, y0;
    105     exgcd( aa, mm, dd, x0, y0 );
    106     x0 = (x0%mm+mm)%mm;
    107     for( dnt k=0; k<d; k++ ) 
    108         stk.push_back( (x0*bb+k*mm)%m );
    109 }
    110 
    111 int main() {
    112     scanf( "%d%d%d", &p, &k, &a );    //    x^k = a mod p
    113     if( a==0 ) {
    114         printf( "1
    0 
    " );
    115         return 0;
    116     }
    117     //    find the root of p: g
    118     g = findroot(p);
    119     //    ind a: b
    120     b = ind( g, a, p );
    121     //    kx=b mod phi(p)
    122     meq( k, b, p-1 );
    123     //    decode
    124     for( int t=0; t<stk.size(); t++ )
    125         stk[t] = mpow( g, stk[t], p );
    126     sort( stk.begin(), stk.end() );
    127     //    output
    128     printf( "%d
    ", stk.size() );
    129     for( int t=0; t<stk.size(); t++ )
    130         printf( "%d ", stk[t] );
    131     printf( "
    " );
    132 }
    View Code
  • 相关阅读:
    layer弹出相册层
    jquery日期和时间的插件精确到秒
    ztree树形菜单的增加删除修改和换图标
    瀑布流插件和模板插件
    使用easyui将json数据生成数据表格
    2013年回顾,2014年计划
    PHP trim去空格函数
    MySql中常用语句
    左右固定,中间自适应布局,中间栏优先加载
    HTML5的全局属性
  • 原文地址:https://www.cnblogs.com/idy002/p/4501633.html
Copyright © 2020-2023  润新知