博士的计算器
题目描述
一日,BY 大神黄犇黄大组长打完羽毛球回来,发现博士正在用魔兽地图编辑器做一个计算器的软件。
因为最近总是一些取模取模的,所以想非常快速的算出来。
简而言之,就是对以下
3
个问题进行讨论。
1.给定
2.给定
y、z、P
,计算满足
yx≡z(modp)
的最小非负整数 。 。
3.给定
y、z、P
,计算
C(z,y)modP
的值 。 (意义为
Z
中取
输入
第一行一个正整数
N
,描述数据组数。
接下来的
对于第
2
种要求,若
输出
要求有 N <script type="math/tex" id="MathJax-Element-20">N</script> 行输出,每行一个整数,为询问的答案。
样例
Sample Input 1 | Sample Output 1 |
---|---|
4 1 2 10 1000 2 3 1 1000 2 2 3 4 3 2 7 9 | 24 0 Math Error 3 |
Sample Input 2 | Sample Output 2 |
4 2 1 2 9 3 1 6 7 1 5 3 7 1 9 2 8 | Math Error 6 6 1 |
数据范围
Solution
操作一:快速幂轻松搞定。
操作二:扩展BSGS算法。
操作三:同 Bzoj2142 礼物
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define LL long long
#define HASH_MOD 999991
using namespace std;
struct map{
LL h[1000010],to[1000010];
void clear(){
memset(h,-1,sizeof h);
}
LL find(LL x){
LL y=x%HASH_MOD;
while(h[y]!=-1&&h[y]!=x)y++;
return h[y]==-1?-1:to[y];
}
void insert(LL x,LL y){
LL z=x%HASH_MOD;
while(h[z]!=-1&&h[z]!=x)z++;
if(h[z]==x)return;
h[z]=x;to[z]=y;
}
}Map;
LL t,Sum,input1,input2,input3,xxx,yyy,ZZZ;
LL p[1000010],ps[1000010],q[1000010],GET[1000010],prime[1000010];
bool no_prime[1000010];
LL gcd(LL x,LL y){
return y==0?x:gcd(y,x%y);
}
LL ex_gcd(LL x,LL y,LL &a0,LL &b0){
if(y==0){
a0=1;b0=0;
return x;
}
LL tx,ty;
LL q=ex_gcd(y,x%y,tx,ty);
a0=ty;
b0=tx-(x/y)*ty;
return q;
}
LL power(LL m,LL n,LL Mod){
if(n==0)return 1;
if(n==1)return m%Mod;
LL tmp=power(m,n/2,Mod);
tmp=tmp*tmp%Mod;
if(n&1)tmp=tmp*m%Mod;
return tmp;
}
void work(LL x){
LL sqr=sqrt(x);
for(LL i=2;i<=sqr;i++){
if(x%i==0){
p[++p[0]]=i;ps[++ps[0]]=i;
q[++q[0]]=1;x/=i;
while(x%i==0){
x/=i;ps[ps[0]]=ps[ps[0]]*i;
q[q[0]]++;
}
}
}
if(x!=1){
p[++p[0]]=x;q[++q[0]]=1;
ps[++ps[0]]=x;
}
}
LL fun(LL x,LL y,LL pre){
if(x==0){
ZZZ=0;
return 1%ps[y];
}
LL Time=x/ps[y],yu=x%ps[y],ans=1,zhishu=0;
ans=ans*power(pre,Time,ps[y])%ps[y];
zhishu+=(x/p[y]);
ans=ans*fun(x/p[y],y,pre)%ps[y];
zhishu+=ZZZ;
for(LL i=Time*ps[y]+1;i<=Time*ps[y]+yu;i++)if(i%p[y]!=0)ans=ans*i%ps[y];
ZZZ=zhishu;
return ans;
}
LL C(LL x,LL y,LL Mod){
if(x>y)return 0;
if(!x)return 1;
LL tmp=1;
for(LL i=1;i<=ps[Mod];i++)if(i%p[Mod]!=0)tmp=tmp*i%ps[Mod];
LL zhishu=0;
LL ans1=fun(y,Mod,tmp);zhishu+=ZZZ;
LL ans2=fun(y-x,Mod,tmp);zhishu-=ZZZ;
LL ans3=fun(x,Mod,tmp);zhishu-=ZZZ;
if(zhishu>q[Mod])return 0;
ex_gcd(ans2*ans3%ps[Mod],ps[Mod],xxx,yyy);
xxx=(xxx%ps[Mod]+ps[Mod])%ps[Mod];
return xxx*ans1%ps[Mod]*power(p[Mod],zhishu,ps[Mod])%ps[Mod];
}
void get(LL m,LL n,LL Mod){
LL ans=0;
p[0]=q[0]=ps[0]=0;
work(Mod);
if(p[0]==1){
printf("%lld\n",C(m,n,1));
return;
}
for(LL i=1;i<=p[0];i++){
ex_gcd(Mod/ps[i],ps[i],GET[i],yyy);
GET[i]=(GET[i]%ps[i]+ps[i])%ps[i];
}
for(LL i=1;i<=p[0];i++)
ans=(ans+C(m,n,i)*(Mod/ps[i])%Mod*GET[i]%Mod)%Mod;
printf("%lld\n",ans);
}
void Baby(LL m,LL n,LL Mod){
Map.clear();
LL cnt=0,fm=m,fn=n%Mod,fMod=Mod,equal=1;n%=Mod;
bool flag=true;
while(1){
LL tmp;
if((tmp=gcd(m,Mod))==1)break;
if(n%tmp!=0){
flag=false;
break;
}
equal=equal*(m/tmp)%fMod;n/=tmp;Mod/=tmp;cnt++;
}
//-------------------------------------------------------
if(1==fn){
printf("0\n");
return;
}
LL Pow=1;
for(LL i=1;i<=cnt;i++){
Pow=Pow*fm%fMod;
if(Pow%fMod==fn){
printf("%lld\n",i);
return;
}
}
//-------------------------------------------------------
if(!flag){
printf("Math Error\n");
return;
}
equal%=Mod;
LL M=ceil(sqrt(Mod));Pow=1;Map.insert(1,0);
for(LL i=1;i<=M;i++){
Pow=Pow*m%Mod;
if(equal*Pow%Mod==n){
printf("%lld\n",i+cnt);
return;
}
Map.insert(Pow,i);
}
LL tmp=Pow;
LL l=ex_gcd(equal*Pow,Mod,xxx,yyy);
if(n%l!=0)goto nxt;{
xxx=(xxx%Mod+Mod)%Mod*(n/l)%(Mod/l);
LL ToToT=Map.find(xxx);
if(ToToT!=-1){
printf("%lld\n",ToToT+M+cnt);
return;
}
}
nxt:;
for(LL i=2;i<=M;i++){
Pow=Pow*tmp%Mod;
LL l=ex_gcd(equal*Pow%Mod,Mod,xxx,yyy);
if(n%l!=0)continue;
xxx=(xxx%Mod+Mod)%Mod*(n/l)%(Mod/l);
LL ToToTT=Map.find(xxx);
if(ToToTT!=-1){
printf("%lld\n",ToToTT+M*i+cnt);
return;
}
}
printf("Math Error\n");
}
inline void in(LL &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
int main(){
freopen("calculator.in","r",stdin);
freopen("calculator.out","w",stdout);
scanf("%lld",&t);
while(t--){
LL SWITCH;
in(SWITCH);in(input1);in(input2);in(input3);
if(input3==1){
printf("0\n");
continue;
}
switch(SWITCH){
case 1:printf("%lld\n",power(input1,input2,input3));break;
case 2:Baby(input1,input2,input3);break;
case 3:get(input1,input2,input3);
}
}
return 0;
}