题目的大意大概就是输入x,z,k(0<=x,z,k<=10^9),输入以0 0 0 结尾,计算满足(x^y)mod z=k,求出满足条件的y.如果找不到满足条件的y,那么直接就输出“No Solusion”(不包含引号).
想着学习也很实在,有模板就直接套模板,我也是这样,没办法,毕竟感觉这些东西有那难懂,只希望自己能够在最短的时间内拿下这些
。
也不知道什么时候能够完完整整的把这些模板学会,完全看懂。。。。
不多说了,直接上模板把,当然出于责任心,小编我也会把我已经了解到的给大家解释下
,虽然理解的不够深,讲解的不够好,但是也希望能帮到你们
:
#include<iostream>
#include<cmath>
#include<cstdio>
#define MAXX 65535//这个可以设置一个比较大的数,只需要大于等于这个65535都行
using namespace std;
struct hash//构造哈希
{
int a,b,next;
}Hash[MAXX<<1];
int flag[MAXX+66];
int top,idx;
void ins(int a,int b)//将b插入到哈希表中的a的位置,当然这也是哈希算法的模板,你可以直接记住就行
{
int k=b&MAXX;
if(flag[k]!=idx)
{
flag[k]=idx;
Hash[k].next=-1;
Hash[k].a=a;
Hash[k].b=b;
return;
}
while(Hash[k].next!=-1)
{
if(Hash[k].b==b)return;
k=Hash[k].next;
}
Hash[k].next=++top;
Hash[top].next=-1;
Hash[top].a=a;
Hash[top].b=b;
}
int find(int b)//在哈希表中查询b的所在位置
{
int k=b&MAXX;
if(flag[k]!=idx)return -1;//这代表并没有找到对应的b,就直接返回-1
while(k!=-1)
{
if(Hash[k].b==b)return Hash[k].a;
k=Hash[k].next;
}
return -1;
}
int gcd(int a,int b)//直接求最大公约数
{
return b==0?a:gcd(b,a%b);
}
int ex_gcd(int a,int b,int &x,int &y)//使用扩展欧几里得算法直接计算ax+by=c里边的x和y的值,并且把a和b的最大公约数返回回去,这个也是一个典型的模板,学习数论的一定需要重点掌握
{
if(!b){x=1;y=0;return a;}
int d=ex_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int inval(int a,int b,int n)找到满足条件的一组解
{
int x,y,e;
ex_gcd(a,n,x,y);
e=(long long)x*b%n;
return e<0?e+n:e;
}
int pow(long long a,int b,int c)//快速幂算法的模板
{
long long ret=1%c;
a%=c;
while(b)
{
if(b&1)ret=ret*a%c;
a=a*a%c;
b>>=1;
}
return ret;
}
int Baby(int a,int b,int c)//解决这道题的关键部分,最关键的函数,我来一一说明
{
top=MAXX;++idx;
long long buf=1%c,D=buf,k;
int i,d=0,tem;//前边都只是定义初始化,挺简单的
for(i=0;i<=100;buf=buf*a%c,++i)//先i从0到100循环验证,如果满足那个条件,直接就返回i
//这里为什么是100呢,因为这个是根据题目给的范围来决定的,题目给出了10^9,也就是说假设X就是1(当然也不是真的1,只是个很接近1的比1大一点的数,因为1的任何次方都是1)那么也就最多需要10*9=90次方才能把那些都试玩,所以这里可以取>=90的任何一个数,不过为了好看点,直接就取了100。
if(buf==b)return i;
while((tem=gcd(a,c))!=1)//这个循环主要是为了得到D,就是那个a=b(mod c)的一个解
{
if(b%tem)return -1;
++d;
c/=tem;
b/=tem;
D=D*a/tem%c;
}
int m=(int)ceil(sqrt((double)c));
for(buf=1%c,i=0;i<=m;buf=buf*a%c,++i)ins(i,buf);//i从0到m循环将(i,a^i%c)插入Hash表中
for(i=0,k=pow((long long)a,m,c);i<=m;D=D*k%c,++i)
{
tem=inval((int)D,b,c);
int w;
if(tem>=0&&(w=find(tem))!=-1)
return i*m+w+d;
}
return -1;
}
int main()
{
int a,b,c;
while(scanf("%d%d%d",&a,&c,&b)!=EOF,a||b||c)//注意输入顺序,我的a对应的是x,b对应的是k,c对应的是Z
{
b%=c;
int tem=Baby(a,b,c);
if(tem<0)puts("No Solution");
else printf("%d\n",tem);
}
return 0;
}
还有道基本上一样的题,大家可以看一下poj 2417
就只需要改变一下输入的顺序,为c,a,b就行