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

来源:互联网 发布:怎么使用爬虫软件 编辑:程序博客网 时间:2024/04/30 07:37
污污污污

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;}
0 0
原创粉丝点击