zoukankan      html  css  js  c++  java
  • 计时器 【扩展欧几里得+BSGS】

    题目:

      https://www.luogu.org/problemnew/show/P2485

    题目简介:

      你被要求设计一个计算器完成以下三项任务:

      1、给定y、z、p,计算y^z mod p 的值;

      2、给定y、z、p,计算满足xy ≡z(mod p)的最小非负整数x;

      3、给定y、z、p,计算满足y^x ≡z(mod p)的最小非负整数x。

      为了拿到奖品,全力以赴吧!

    题解:

      问题一: 二分快速幂

     1 ll Make(ll x,ll y,ll mod){
     2     if(y==0) return 1%mod;
     3     ll mid=y/2;
     4     ll ans=Make(x,mid,mod);
     5     ans=(ans*ans)%mod;
     6     if(y&1){ans=(ans*x)%mod;}
     7     return ans; 
     8 }
     9 void Next1(){
    10     Read(Y),Read(Z),Read(P);
    11     ll ans=Make(Y,Z,P);
    12     Write(ans);
    13     return ;
    14 }
    View Code

      问题二: 扩展欧几里得模板

     1 ll ExGcd(ll a,ll b,ll &x,ll &y){
     2     if(b==0) {
     3         x=1;
     4         y=0;
     5         return a;
     6     }
     7     ll res=ExGcd(b,a%b,y,x);
     8     y-=a/b*x;
     9     return res;
    10 }
    11 void Next2(){
    12     Read(Y),Read(Z),Read(P);
    13     ll x,y,res;
    14     if(Y==0 && Z!=0){
    15         printf("Orz, I cannot find x!
    ");
    16         return ;
    17     }
    18     res=ExGcd(Y,P,x,y);    
    19     if(Z%res){
    20         printf("Orz, I cannot find x!
    ");
    21         return ;
    22     }
    23     x=((Z/res*x%P)+P)%(P/res);
    24     Write(x);
    25     return ;
    26 }
    View Code

      问题三:BabyStepGiantStep 【BSGS】

        对于幂取模,直接硬来(枚举指数)时间复杂度是过不去的

      对于BSGS的理解:

        对于 y^x ≡ z (mod p)

        根据抽屉原理: y^(p+k) mod p 的值一定存在于 y^(1~p) mod p 中(因为mod p最多有p个值)

        所以我们的考虑范围也就从 inf 缩小到了 p,但,这仍然是不够的

        思考继续缩小考虑范围

        想到分治,讲y^(1~p)分解为A部分 y^(1~m)  和B部分 y^(m+1~p) 

        考虑两者间的连系

          对于B部分的y^j   j一定满足  j=x+k*m  (k*m 是为了保障x<m)

          那么y^j=y^x  *  y^(k*m)    

          也就是说我们需要运算的也就化为了m+(p-m)  (最坏情况)

          为了应对最坏情况选择 m=sqrt(p)

     实现方法(BSGS):

        根据前面分析,我们只需要预处理 y^(1~m) 的结果  (注意离散化储存)

        然后枚举 y^(k*m) 并通过 方程 : a*y^(k*m)+b*p=z  解出所需值 a  (即分析中的 y^x)

        而 a 若是预处理过的值,即找到了 原方程的解

     

     1 const int Hash=100003;
     2 int Tot;
     3 int F[Hash+5];
     4 struct data{
     5     ll to,cost;
     6     int next;
     7 }E[Hash*10];
     8 void Addl(int x,ll y,ll z){
     9     E[++Tot]=(data){y,z,F[x]};
    10     F[x]=Tot;
    11     return ;
    12 }
    13 int H(ll x){
    14     return abs(x)%Hash;
    15 }
    16 ll Updata(int op,ll x,ll z){
    17     int t=H(x);
    18     int i=F[t];
    19     while(i){
    20         if(E[i].to==x) return E[i].cost;
    21         i=E[i].next;
    22     }
    23     if(op==0) return 0;
    24     Addl(t,x,z);
    25     return 0;
    26 }
    27 void Next3(){
    28     Read(Y),Read(Z),Read(P);
    29     if(Z==1){
    30         putchar('0');putchar('
    ');
    31         return ; 
    32     }
    33     if(Y==0 || Y%P==0){
    34         printf("Orz, I cannot find x!
    ");
    35         return ;
    36     }
    37     Tot=0;
    38     ll tmp=1;
    39     memset(F,0,sizeof(F));
    40     
    41     int m=sqrt(P);
    42     if(m*m<P) m++;
    43     Updata(1,1,m+1);
    44     for(ll i=1;i<m;i++){
    45         tmp=(tmp*Y)%P;
    46         Updata(1,tmp,i);
    47     }
    48     tmp=(tmp*Y)%P;
    49     ll ok=1,x,y;
    50     for(ll i=0;i<m;i++){
    51         ll res=ExGcd(ok,P,x,y);
    52         ll need=(((Z/res*x)%P)+P)%(P/res);
    53         ll opi=Updata(0,need,0);
    54         if(opi>0){
    55             if(opi==m+1) opi=0;
    56             Write(opi+m*i);
    57             return ;
    58         }
    59         ok=(ok*tmp)%P;
    60     }
    61     printf("Orz, I cannot find x!
    ");
    62     return ;
    63 }
    部分代码

    总代码

      1 #include<cmath>
      2 #include<queue>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 typedef long long ll;
      9 int T,K;
     10 ll Y,Z,P;
     11 void Read(ll &x){
     12     x=0;
     13     char c=getchar();
     14     while(!isdigit(c)) c=getchar();
     15     while(isdigit(c)) x=x*10-'0'+c,c=getchar();
     16     return ;
     17 }
     18 ll Make(ll x,ll y,ll mod){
     19     if(y==0) return 1%mod;
     20     ll mid=y/2;
     21     ll ans=Make(x,mid,mod);
     22     ans=(ans*ans)%mod;
     23     if(y&1){ans=(ans*x)%mod;}
     24     return ans; 
     25 }
     26 void Write(ll x){
     27     int np=0;
     28     int s[500];
     29     while(x) s[++np]=x%10,x/=10;
     30     if(!np) s[++np]=0;
     31     while(np) putchar(s[np--]+'0');
     32     putchar('
    ');
     33     return ;
     34 }
     35 void Next1(){
     36     Read(Y),Read(Z),Read(P);
     37     ll ans=Make(Y,Z,P);
     38     Write(ans);
     39     return ;
     40 }
     41 ll ExGcd(ll a,ll b,ll &x,ll &y){
     42     if(b==0) {
     43         x=1;
     44         y=0;
     45         return a;
     46     }
     47     ll res=ExGcd(b,a%b,y,x);
     48     y-=a/b*x;
     49     return res;
     50 }
     51 void Next2(){
     52     Read(Y),Read(Z),Read(P);
     53     ll x,y,res;
     54     if(Y==0 && Z!=0){
     55         printf("Orz, I cannot find x!
    ");
     56         return ;
     57     }
     58     res=ExGcd(Y,P,x,y);    
     59     if(Z%res){
     60         printf("Orz, I cannot find x!
    ");
     61         return ;
     62     }
     63     x=((Z/res*x%P)+P)%(P/res);
     64     Write(x);
     65     return ;
     66 }
     67 const int Hash=100003;
     68 int Tot;
     69 int F[Hash+5];
     70 struct data{
     71     ll to,cost;
     72     int next;
     73 }E[Hash*10];
     74 void Addl(int x,ll y,ll z){
     75     E[++Tot]=(data){y,z,F[x]};
     76     F[x]=Tot;
     77     return ;
     78 }
     79 int H(ll x){
     80     return abs(x)%Hash;
     81 }
     82 ll Updata(int op,ll x,ll z){
     83     int t=H(x);
     84     int i=F[t];
     85     while(i){
     86         if(E[i].to==x) return E[i].cost;
     87         i=E[i].next;
     88     }
     89     if(op==0) return 0;
     90     Addl(t,x,z);
     91     return 0;
     92 }
     93 void Next3(){
     94     Read(Y),Read(Z),Read(P);
     95     if(Z==1){
     96         putchar('0');putchar('
    ');
     97         return ; 
     98     }
     99     if(Y==0 || Y%P==0){
    100         printf("Orz, I cannot find x!
    ");
    101         return ;
    102     }
    103     Tot=0;
    104     ll tmp=1;
    105     memset(F,0,sizeof(F));
    106     
    107     int m=sqrt(P);
    108     if(m*m<P) m++;
    109     Updata(1,1,m+1);
    110     for(ll i=1;i<m;i++){
    111         tmp=(tmp*Y)%P;
    112         Updata(1,tmp,i);
    113     }
    114     tmp=(tmp*Y)%P;
    115     ll ok=1,x,y;
    116     for(ll i=0;i<m;i++){
    117         ll res=ExGcd(ok,P,x,y);
    118         ll need=(((Z/res*x)%P)+P)%(P/res);
    119         ll opi=Updata(0,need,0);
    120         if(opi>0){
    121             if(opi==m+1) opi=0;
    122             Write(opi+m*i);
    123             return ;
    124         }
    125         ok=(ok*tmp)%P;
    126     }
    127     printf("Orz, I cannot find x!
    ");
    128     return ;
    129 }
    130 int main(){
    131     scanf("%d%d",&T,&K);
    132     while(T--)
    133     if(K==1) Next1();
    134     else if(K==2) Next2();
    135     else Next3(); 
    136     return 0;
    137 }
    Code

        

        

  • 相关阅读:
    中断向量表
    内核进程的堆栈 [转]
    int指令理解
    Linux进程创建和结束
    Linux 信号signal处理机制
    wait和waitpid详解
    linux 如何清理僵尸进程
    API:System V & POSI
    shell
    Code POJ
  • 原文地址:https://www.cnblogs.com/Aloyd/p/9296666.html
Copyright © 2011-2022 走看看