您的位置:首页 > 其它

[bzoj2242][SDOI2011]计算器

2017-04-18 08:59 302 查看
来自FallDream的博客,未经允许,请勿转载,谢谢。

你被要求设计一个计算器完成以下三项任务:
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)的最小非负整数。
1<=y,z,p<=10^9
第一问快速幂 第二问exgcd 第三问bsgs

然后bsgs的时候感觉写$y^{ax-b}=z$比较舒服,这样$y^b$可以直接乘到右边

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
inline 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 n,k,y,z,p,MN;
ll a,b;
map<int,int> mp;

int pow(int x,int k,int mod)
{
if(mod==1) return 0;
int sum=1;
for(;k;k>>=1,x=1LL*x*x%mod)
if(k&1) sum=1LL*sum*x%mod;
return sum;
}

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

int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
if(k==1)
{
for(int i=1;i<=n;i++)
y=read(),z=read(),p=read(),printf("%d\n",pow(y,z,p));
}
if(k==2)
{
for(int i=1;i<=n;i++)
{
y=read(),z=read(),p=read();
int c=exgcd(y,p,a,b);
if(z%c) puts("Orz, I cannot find x!");
else y/=c,z/=c,p/=c,printf("%lld\n",((a*z/c)%p+p)%p);
}
}
if(k==3)
{
for(int i=1;i<=n;i++)
{
mp.clear();
y=read();z=read();p=read();y%=p;MN=ceil(sqrt(p));
if(!y&&!z)puts("1");else
if(!y)puts("Orz, I cannot find x!");
else if(p==1) puts("0");
else
{
int times=pow(y,MN,p);bool flag=0;
for(int j=0,k=z%p;j<=MN;j++,k=1LL*k*y%p)
mp[k]=j;
for(int j=1,k=times;j<MN;j++,k=1LL*k*times%p)
if(mp[k]) {flag=1,printf("%lld\n",1LL*j*MN-mp[k]);break;}
if(!flag) puts("Orz, I cannot find x!");
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: