博士的计算器 [师大集训 Day 3]

45 篇文章 0 订阅
2 篇文章 0 订阅

博士的计算器


题目描述

一日,BY 大神黄犇黄大组长打完羽毛球回来,发现博士正在用魔兽地图编辑器做一个计算器的软件。
因为最近总是一些取模取模的,所以想非常快速的算出来。
简而言之,就是对以下 3 个问题进行讨论。
1.给定 yzP,计算 yzmodp 的值;
2.给定 yzP ,计算满足 yxz(modp) 的最小非负整数 。 。
3.给定 yzP ,计算 C(z,y)modP 的值 。 (意义为 Z 中取 Y 的组合)


输入

第一行一个正整数 N ,描述数据组数。
接下来的 N 行,每行 4 个正整数 Sum y z p
Sum 表述询问类型,如上所述。
对于第 2 种要求,若 X 不存在,则输出“Math Error ”


输出

要求有 N <script type="math/tex" id="MathJax-Element-20">N</script> 行输出,每行一个整数,为询问的答案。


样例

Sample Input 1Sample 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 2Sample 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值