题意:给定一个整数k和mod,给定若干个仅有数字和小写字母构成的字符串,对于每一个字符串,将其看成一个p进制数('a'看做10...'z'看做35,故p<=36),然后求出其对应的十进制数tot,然后求(k^{tot})%mod.
分析:本题将用到快速幂模板,扩展欧拉定理以及分解质因数法求欧拉函数(卖个广告关于欧拉函数及定理,无证明)
首先暴力思路不难想到,直接按照题意一步步求,但是要知道最大是长度为(10^5)的36进制数,即便开了long long,也能够轻松爆掉.我们的问题在于,无法将一个长度为(10^5)的36进制数转化为long long类型?
目前我只知道两种做法,第一种是根据二进制快速幂巧妙设计出p进制快速幂(假设是求(x^e)):
qp(ll x,ll e,ll p) {
ll res=1;
while(e){
取出e的最后一位t,去掉e的最后一位;
res*=x^t;
x=x^p;
}
return res;
}
我写的是第二种做法,我们现在是要求(k^{tot}),因为在求tot时会爆long long,于是要用到扩展欧拉定理:当a,n不一定互质,且b>=φ(n)时,有(a^b≡a^{b mod φ(n)+φ(n)})(mod n),所以我们在求tot时,就可以一边求一边对φ(mod)取模,这样tot就不会爆long long了.
于是可以先用分解质因数法求出phi(mod),然后求tot时对phi(mod)取模,最后求(k^{tot}+phi(mod))
int shu[100005];
char ch[100005];
int jz(char s){
if(s>='0'&&s<='9')return s-'0';
else return s-'a'+10;
}
ll qp(ll a,ll b,ll c){
ll res=1;
while(b){
if(b&1)res=(res*a)%c;
a=(a*a)%c;
b=b/2;
}
return res%c;
}//快速幂模板
int phi(int x){
int y=x;
for(int i=2;i*i<=x;i++){
if(x%i==0){
y=y/i*(i-1);
while(x%i==0)x/=i;
}
}
if(x>1)y=y/x*(x-1);
return y;
}//分解质因数法求欧拉函数
int main(){
int k=read(),mod=read();
while(~(scanf("%s",ch))){
int len=strlen(ch),maxn=0,pos=-1;
for(int i=0;i<len;i++){
shu[i]=jz(ch[i]);
if(shu[i]>maxn)maxn=shu[i];
if(pos==-1&&shu[i]!=0)pos=i;
//这个pos是为了避开前导零,节约时间,但是好像也没必要
}
++maxn;//进制
ll tot=0;
int cnt=-1,res=phi(mod);
for(int i=len-1;i>=pos;i--){
++cnt;
int now=shu[i];
if(!now)continue;//是零就跳过不求,也没什么必要
tot+=now*qp(maxn,cnt,res);
}
printf("%lld
",qp(k,tot+res,mod));
}
return 0;
}