BSGS

【Bzoj】3122: [Sdoi2013]——随机数生成器(大步小步算法)

Time Limit: 10 Sec Memory Limit: 256 MB

Description

Input

输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数。

接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据。保证X1和t都是合法的页码。

注意:P一定为质数

Output

共T行,每行一个整数表示他最早读到第t页是哪一天。如果他永远不会读到第t页,输出-1。

Sample Input

3

7 1 1 3 3

7 2 2 2 0

7 2 2 2 1

Sample Output

1

3

-1

HINT

0<=a<=P-1,0<=b<=P-1,2<=P<=10^9

中文题意,就不解释了。对于公式

xi+1=a(xi+b)(modp)
我们明显看到后面的结果前面的决定。那么我们列举一下
x1=x1x2=ax1+b(modp)x3=ax2+b=a(ax1+b)+b=a2x1+ab+bx4=ax3+b=a3x1+a2b+ab+bxn=an1x1+an2b++b=an1x1+ban11a1(modp)
通过推导出来的公式,由于a,b,p ,t, x1 都是已知的,那么所求的就是
xn=an1x1+ban11a1=t(modp)
设a-1的逆元是c,那么
an1(cx1+b)=(tc+b)(modp)
再转化一下
an1=(tc+b)×inv(cx1+b)(modp)
,问题明显就是求n,就是离散对数,用bsgs(大步小步算法)算法即可求得,不过要特判一下当a = 0,a = 1的时候

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#define rr() freopen("in.in","r",stdin)
#define ww() freopen("out.out","w",stdout)
using namespace std;
typedef long long LL;
LL a,b,p,x1,t;
void exgcd(LL A,LL B,LL &g,LL &x,LL &y){//扩展欧几里得
    if(B == 0){
        g = A;
        x = 1;
        y = 0;
        return ;
    }
    else{
        exgcd(B,A%B,g,y,x);
        y-=(A/B)*x;
    }
}
LL INV(LL A,LL B){//求逆元
    LL g,x,y;
    exgcd(A,B,g,x,y);
    return g==1?(x%B+B)%B:-1;
}
LL cal1(){
    t = ((t-x1)%p+p)%p;
    LL ans = INV(b,p);
    if(ans == -1) return ans;
    else return (ans*t)%p+1;
}
LL Pow(LL A, LL m){
    LL ans = 1;
    while(m){
        if(m%2) ans = (ans*A)%p;
        A = (A*A)%p;
        m>>=1;
    }
    return ans;
}
LL bsgs(LL A, LL B,LL n){
    A%=n;
    if(!A){
        if(!B) return 1;
        else return -1;
    }
    LL m = (LL)sqrt(n)+1;
    LL inv = INV(Pow(A,m),n);
    if(inv == -1)  return -1;
    map<LL,LL>mp;mp.clear();
    mp[1] = 0;
    LL e= 1;
    for(int i = 1;i<m;i++){
        e = (e*A)%p;
        if(!mp.count(e)) mp[e] = i;
    }
    for(int i =0;i<m;i++){
        if(mp.count(B)) return m*i+mp[B];
        B =(inv*B)%p;
    }
    return -1;
}

LL cal2(){
    LL inv = INV(a-1,p);
    x1 =(x1+b*inv)%p;
    t = (t+b*inv)%p;
    LL inv2 =INV(x1,p);
    if(inv2 == -1) return -1;
    t = (t*inv2)%p;
    LL ans  = bsgs(a,t,p);
    return ans == -1?ans:ans+1;
}
LL solve(){
    if(x1 == t) return 1;
    if(a ==0) {
        if(b == t) return 2;
        else return -1;
    }
    if(a == 1) return cal1();
    else return cal2();
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lld %lld %lld %lld %lld",&p,&a,&b,&x1,&t);
        printf("%lld\n",solve());
    }
    return 0;
}

【Bzoj】2242: [SDOI2011]——计算器

Time Limit: 10 Sec Memory Limit: 512 MB

Description

你被要求设计一个计算器完成以下三项任务:
1、给定y,z,p,计算Y^Z Mod P 的值;
2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;
3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。

Input

输入包含多组数据。
第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。

Output

对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。

Sample Input

【样例输入1】

3 1

2 1 3

2 2 3

2 3 3

【样例输入2】

3 2

2 1 3

2 2 3

2 3 3

【数据规模和约定】

对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。

Sample Output

【样例输出1】

2

1

2

【样例输出2】

2

1

0

Source

第一轮day1

三种操作,快速幂,扩展欧几里得,离散对数。在处理原根 ax=b(modp) 的时候,要特判a = 0的情况。

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <algorithm>

using namespace std;

typedef long long LL;
LL y,z,p;
LL Pow(LL n,LL m){
    n%=p;
    LL ans =1 ;
    while(m){
        if(m&1) ans = (ans*n)%p;
        n = (n*n)%p;
        m>>=1;
    }
    return ans;
}
void exgcd(LL a,LL b,LL &g,LL &fx ,LL &fy){
    if(b == 0){
        g = a;
        fx = 1;
        fy = 0;
    }
    else {
        exgcd(b,a%b,g,fy,fx);
        fy-=fx*(a/b);
    }
}
LL Inv()
{
    LL g,fx,fy;
    exgcd(y,p,g,fx,fy);
    if(z%g) return -1;
    y/=g;z/=g;p/=g;
    return ((fx*z)%p+p)%p;
}

LL bsgs(LL a,LL b, LL n){
    a%=n;
    if(!a && !b) return 1;
    if(!a) return -1;
    LL m = (LL)sqrt(n)+1;
    LL inv = Pow(Pow(a,m),n-2);
    map<LL,LL>mp; mp.clear();
    mp[1] = 0;
    LL st = 1;
    for(int i =1;i<m;i++){
        st=(st*a)%p;
        if(!mp.count(st)) mp[st] = i;
    }
    for(int i = 0;i<m;i++){
        if(mp.count(b)) return i*m+mp[b];
        b = (b*inv)%p;
    }
    return -1;
}
int main(){
    int T,k;
    while(~scanf("%d %d",&T,&k)){
        while(T--){
            scanf("%lld %lld %lld",&y,&z,&p);
            if(k == 1) printf("%lld\n",Pow(y,z));
            else if(k == 2){
                LL ans = Inv();
                if(ans == -1) printf("Orz, I cannot find x!\n");
                else printf("%lld\n",ans);
            }
            else{
                LL ans = bsgs(y,z,p);
                if(ans == -1) printf("Orz, I cannot find x!\n");
                else printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(BSGS)