2018.12.18 bzoj2242: [SDOI2011]计算器(数论)

传送门

数论基础题。

对于第一种情况用快速幂,第二种用exgcdexgcdexgcd,第三种用bsgsbsgsbsgs


于是自己瞎yyyyyy了一个bsgsbsgsbsgs的板子(不知道是不是数据水了没卡如果有找出错的希望指正谢谢)

下面谈谈我对这个方法的理解。

实际上跟网上说的差不多。

要解ax≡bmod  pa^x\equiv b\mod pax≡bmodp

相当于令p=k∗A+B,0≤B&lt;pp=k*A+B,0\le B&lt;pp=k∗A+B,0≤B<p

然后假设x=k′∗A+B′,0≤B′&lt;px=k'*A+B',0\le B'&lt;px=k′∗A+B′,0≤B′<p

那么(aA)k′≡b∗(a−1)B′(a^A)^{k'}\equiv b*(a^-1)^{B'}(aA)k′≡b∗(a−1)B′

于是枚举k′k'k′和B′B'B′即可,可以想到在AAA取sqrtpsqrt_psqrtp​的时候最坏复杂度最优。

代码:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
typedef long long ll;
inline int ksm(int a,int p,int mod){int ret=1;for(;p;p>>=1,a=(ll)a*a%mod)if(p&1)ret=(ll)ret*a%mod;return ret;}
inline int gcd(int a,int b){while(b){int t=a;a=b,b=t%a;}return a;}
inline 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;
}
inline int bsgs(int a,int b,int mod){
	a%=mod,b%=mod;
	if(!a&&!b)return 1;
	if(!a)return -1;
	tr1::unordered_map<int,int>S;
	int sqr=ceil(sqrt(mod-1)),inv=ksm(a,mod-2,mod);
	for(ri i=0,mul=b;i<sqr;++i,mul=(ll)mul*inv%mod)if(!S[mul])S[mul]=i?i:sqr;
	a=ksm(a,sqr,mod);
	for(ri i=0,mul=1;i*sqr<=mod;++i,mul=(ll)mul*a%mod)if(S[mul])return i*sqr+(S[mul])%sqr;
	return -1;
}
int main(){
	freopen("lx.in","r",stdin);
    for(ri a,b,p,tt=read(),k=read();tt;--tt){
        a=read(),b=read(),p=read();
        if(k==1){cout<<ksm(a%p,b,p)<<'\n';continue;}
        if(k==2){
            a%=p,b%=p;
            int g=gcd(a,p),x,y;
            if(b%g){puts("Orz, I cannot find x!");continue;}
            a/=g,b/=g,p/=g,exgcd(a,p,x,y),x=((ll)b*x%p+p)%p,cout<<x<<'\n';
            continue;
        }
        int tmp;
        if(~(tmp=bsgs(a,b,p)))cout<<tmp<<'\n';
        else puts("Orz, I cannot find x!");
    }
    return 0;
}
上一篇:python中字典内置方法


下一篇:JavaScript模拟*落体