BZOJ-2242 计算器 快速幂+拓展欧几里得+BSGS(数论三合一)

污污污污

2242: [SDOI2011]计算器
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 2312 Solved: 917
[Submit][Status][Discuss]

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

HINT

Source
第一轮day1

第一问:快速幂直接搞;
第二问:拓展欧几里得直接搞;
第三问:BSGS直接搞;

安利一下BSGS的大体框架:
首先要求 a^x=b (mod c)
假定x=im-j (m=ceil(sqrt(n)))
那么进行变换:
a^im = b*a^j (mod c)
枚举b*a^j mod p的值存入哈希表(map)。
再枚举a^im的值,从哈希表里找,如果能找到一样的答案就是i*m-j

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>

using namespace std;
int n;

int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

int gcd(int a,int b)
{
    if (!b) return a;
       else return gcd(b,a%b);
}

void exgcd(int a,int b,int &x,int &y)
{
    if (!b) {x=1,y=0;return;}
    exgcd(b,a%b,x,y);
    int t=x;x=y;
    y=t-a/b*y;
}

long long quick_pow(long long a,int b,int p)//返回a^b%p的值
{
    long long re=1;
    long long tmp=a%p;
    while (b)
        {
            if (b&1)
                re=(re*tmp)%p;
            tmp=(tmp*tmp)%p;
            b=b>>1;
        }
    return re;
}


void work1(int a,int b,int c) 
{
    printf("%lld\n",quick_pow(a,b,c));
}
void work2(int a,int b,int c) 
{ 
    c=-c;
    int gc=gcd(a,c); 
    if (b%gc!=0) {puts("Orz, I cannot find x!");return;}
    a/=gc;b/=gc;c/=gc;
    int x,y;exgcd(a,c,x,y);
    x=(long long)x*b%c;
    while (x<0) x+=c;
    printf("%d\n",x);
}
void work3(int a,int b,int c)
{
    map<int,int>mp;mp.clear();
    if (a%c==0) {puts("Orz, I cannot find x!");return;}
    int m=ceil(sqrt(c));
    long long t=b;
    for (int i=0; i<=m; i++)
        {
            mp[(int)t]=i;
            t=t*a%c;
        }
    int s=quick_pow(a,m,c);t=s;
    for (int i=1; i<=m; i++)
        {
            int v=mp[(int)t];
            if (v!=0) {printf("%d\n",i*m-v);return;}
            t=t*s%c; 
        }
    puts("Orz, I cannot find x!");
}

int main()
{
    int t=read(),k=read();
    for (int i=1; i<=t; i++)
        {
            int y=read(),z=read(),p=read();
            if (k==1) work1(y,z,p);
            if (k==2) work2(y,z,p);
            if (k==3) work3(y,z,p);
        }
    return 0;
}
posted @ 2016-02-17 14:41  DaD3zZ  阅读(286)  评论(0编辑  收藏  举报