bzoj 2242 计算器

数论裸题,只要会算法即可。
膜拜了bsgs,注意以下几个点
1.y要先模p,特判y=0,z=0情况
2.y^x不要用快速幂求,累乘即可
3.小步的时候不要忘*z

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

//#define md
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 1000010
using namespace std;

struct ha
{
int a[N],pos[N];
int mxn;
void clear() { memset(a,-1,sizeof(a)); mxn=1000000;}
void insert(int x,int ps)
{
int now=x%mxn;
while (a[now]!=-1) {now++; if (now>mxn) now=1; }
a[now]=x; pos[now]=ps;
}
int find(int x)
{
int now=x%mxn;
while (a[now]!=-1) { if (a[now]==x) return pos[now]; now++; if (now>mxn) now=1; }
return -1;
}
}hash;

int mi(ll a,int b,int md)
{
ll ans=1;
while (b)
{
if (b&1) ans=ans*a%md;
a=a*a%md; b>>=1;
}
return (int)ans;
}
int ni(ll a,int md) { return mi(a,md-2,md); }
int gcd(int a,int b) { return b==0?a:gcd(b,a%b);}
void exgcd(int a,int b,ll &x,ll &y)
{
if (b==0) { x=1; y=0; return; }
exgcd(b,a%b,x,y);
ll t=y; y=x-(a/b)*y; x=t;
}

int main()
{
int tt,opt;
scanf("%d%d",&tt,&opt);
while (tt--)
{
switch (opt)
{
case 1:
{
ll a; int b,md;
scanf("%lld%d%d",&a,&b,&md);
printf("%d\n",mi(a,b,md));
break;
}
case 2:
{
int a,b,c;
scanf("%d%d%d",&a,&c,&b);
int t=gcd(a,b);
if (c%t) { printf("Orz, I cannot find x!\n"); continue;}
a/=t; b/=t; c/=t;
ll x,y;
exgcd(a,b,x,y);
x=x*c%b; while (x<0) x+=b;
printf("%lld\n",x);
break;
}
case 3:
{
ll y,z; int md;
scanf("%lld%lld%d",&y,&z,&md);
y%=md;
if (!y&&!z) { printf("1\n"); continue;}
if (!y) { printf("Orz, I cannot find x!\n"); continue;}
int m=sqrt(md-1),ans=-1;
ll ji=z,nic=ni(y,md);
hash.clear();
for (int i=0;i<m;i++) { hash.insert((int)ji,i); ji=ji*nic%md;}
ji=1; ll c=mi(y,m,md);
for (int i=0;i<m;i++)
{
int x=hash.find(ji);
if (x!=-1) { ans=i*m+x; break; }
ji=ji*c%md;
}
if (ans==-1) printf("Orz, I cannot find x!\n"); else printf("%d\n",ans);
break;
}
}
}
return 0;
}


你可能感兴趣的:(bzoj 2242 计算器)