牛客小白月赛12 392B

链接:https://ac.nowcoder.com/acm/contest/392/B
来源:牛客网

题目描述

找到了心仪的小姐姐月月后,华华很高兴的和她聊着天。然而月月的作业很多,不能继续陪华华聊天了。华华为了尽快和月月继续聊天,就提出帮她做一部分作业。
月月的其中一项作业是:给定正整数A、B、P,求 ABmodPABmodP的值。华华觉得这实在是毫无意义,所以决定写一个程序来做。但是华华并不会写程序,所以这个任务就交给你了。
因为月月的作业很多,所以有T组询问。

输入描述:

第一行一个正整数T表示测试数据组数。
接下来T行,每行三个正整数A、B、P,含义如上文。

输出描述:

输出T行,每行一个非负整数表示答案。
示例1

输入

复制
2
2 5 10
57284938291657 827493857294857 384729583748273

输出

复制
2
18924650048745

备注:

1T1031≤T≤103,1A,B,P1018

方法一 直接用大数模板加快速幂计算
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cmath>
#include <bitset>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <algorithm>
using namespace std;

typedef long long  ll;
#define mem(a, x) memset(a, x, sizeof a)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
#define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))

ll powermod(ll a, ll exp, ll moder){
    ll ret = 1;
    for ( ; exp; exp >>= 1){
        if (exp & 1){
            ret = 1ll * ret * a % moder;
        }
        a = 1ll * a * a % moder;
    }
    return ret;
}

void addminus(int *a, int *b, int &lengtha, int &lengthb, int type){
    int length = std::max(lengtha, lengthb);
    for (int i = 0; i < length; ++ i){
        a[i] += type == 1 ? b[i] : -b[i];
        a[i] >= 10 ? (a[i] -= 10, ++ a[i + 1]) : a[i] < 0 ? (a[i] += 10, -- a[i + 1]) : 0;
    }
    for (lengtha = length + 1; lengtha && !a[lengtha - 1]; -- lengtha);
}

struct biginteger{
    // 3y·¨oí?a?ùdèòa??±?????
    const static int max = 6; //2^max位数字
    const static int moder = (119 << 23) + 1;
    const static int root = 3;
    const static int invroot = 332748118;

    int a[1 << max];
    int length, sig;

    biginteger(){
        memset(a, 0, sizeof(a));
        length = sig = 0;
    }

    void clear(){
        memset(a, 0, sizeof(int) * length);
        length = sig = 0;
    }

    void read(){
        clear();
        char ch = getchar();
        for ( ; (ch < '0' || ch > '9') && ch != '-'; ch = getchar())
            ;
        ch == '-' ? (sig = -1, ch = getchar()) : sig = 1;
        for ( ; ch >= '0' && ch <= '9'; ch = getchar()){
            a[length ++] = ch - '0';
        }
        std::reverse(a, a + length);
        for ( ; length && !a[length - 1]; -- length)
            ;
        sig = length ? sig : 0;
    }

    void print(){
        if (!sig) return (void)putchar('0');
        if (sig < 0){
            putchar('-');
        }
        for (int i = length - 1; i >= 0; i--){
            putchar(a[i] + '0');
        }
    }

    template <typename t>
    t tointeger(){
        t ret = 0;
        for (int i = length - 1; i >= 0; ++ i){
            ret = ret * 10 + a[i];
        }
        return ret * sig;
    }
    ll tointeger(){
        ll ret = 0;
        for (int i = length - 1; i >= 0; ++ i){
            ret = ret * 10 + a[i];
        }
        return ret * sig;
    }

    bool equal(const biginteger &p) const &{
        if (sig != p.sig || length != p.length)    return false;
        for (int i = 0; i < length; ++ i){
            if (a[i] != p.a[i])    return false;
        }
        return true;
    }

    bool greater(const biginteger &p) const &{
        if (sig != p.sig) return sig > p.sig;
        if (length != p.length) return length > p.length ^ sig == -1;
        for (int i = length - 1; i >= 0; -- i){
            if (a[i] > p.a[i]) return sig > 0;
            else if (a[i] < p.a[i]) return sig < 0;
        }
        return false;
    }

    void leftshift(int dis){
        for (int i = length + dis - 1; i >= dis; -- i){
            a[i] = a[i - dis];
        }
        memset(a, 0, sizeof(int) * dis);
        length += dis;
    }

    void rightshift(int dis){
        if (dis >= length) return clear();
        for (int i = 0; i < length - dis; ++ i){
            a[i] = a[i + dis];
        }
        memset(a + length - dis, 0, sizeof(int) * dis);
        length = length - dis > 0 ? length - dis : 0;
    }

    void addone(){
        sig >= 0 ? ++ a[0] : -- a[0];
        for (int i = 0; i < length; ++ i){
            if (a[i] < 10 && a[i] >= 0) break;
            a[i] >= 10 ? (a[i] -= 10, ++ a[i + 1]) : (a[i] += 10, -- a[i + 1]);
        }
        if (a[length]){
            ++ length;
        }
        if (!a[length - 1]){
            -- length;
        }
        sig = length ? (sig >= 0 ? 1 : -1) : 0;
    }

    void minusone(){
        sig = -sig;
        addone();
        sig = -sig;
    }

    bool absgreaterequal(biginteger &q){
        if (length != q.length) return length > q.length;
        for (int i = length - 1; i >= 0; -- i){
            if (a[i] > q.a[i]) return true;
            if (a[i] < q.a[i]) return false;
        }
        return true;
    }

    void abs(){
        sig = std::abs(sig);
    }

    void neg(){
        sig = -sig;
    }

    void assign(biginteger &q){
        memset(a, 0, sizeof(int) * length);
        memcpy(a, q.a, sizeof(int) * q.length);
        length = q.length;
        sig = q.sig;
    }

    void assign2(ll q){
        memset(a, 0, sizeof(int) * length);
        if (!q) return (void) (sig = length = 0);
        q < 0 ? sig = -1, q = -q : sig = 1;
        length = 0;
        for ( ; q; q /= 10){
            a[length ++] = q % 10;
        }
        //cout<<"length: "<<length<<endl;
    }

    template <typename t>
    void assign(t q){
        memset(a, 0, sizeof(int) * length);
        if (!q) return (void) (sig = length = 0);
        q < 0 ? sig = -1, q = -q : sig = 1;
        length = 0;
        for ( ; q; q /= 10){
            a[length ++] = q % 10;
        }
    }

    void add(biginteger &q){
        static biginteger aux;
        if (!q.sig) return;
        if (!sig){
            assign(q);
            return;
        }
        if (sig == q.sig){
            addminus(a, q.a, length, q.length, 1);
            return;
        }
        if (absgreaterequal(q)){
            addminus(a, q.a, length, q.length, -1);
            sig = length ? sig : 0;
            return;
        }
        aux.assign(q);
        addminus(q.a, a, q.length, length, -1);
        assign(q);
        q.assign(aux);
    }

    void minus(biginteger &q){
        q.neg();
        add(q);
        q.neg();
    }

    void ntt(int *a, int length, int type){
        int len = -1;
        for (int x = length; x; ++ len, x >>= 1);
        for(int i = 1, j = 0; i < length - 1; ++ i){
            for(int s = length; j ^= s >>= 1, ~j & s; )
                ;
            if(i < j){
                std::swap(a[i], a[j]);
            }
        }
        for (int i = 1; i <= len; ++ i){
            for (int j = 0, unit = powermod(type == 1 ? root : invroot, moder - 1 >> i, moder), szk = 1 << i - 1; j < length; j += 1 << i){
                for (int k = j, w = 1; k < j + szk; ++ k){
                    int s = a[k], t = 1ll * w * a[k + szk] % moder;
                    a[k] = s + t >= moder ? s + t - moder : s + t;
                    a[k + szk] = s - t < 0 ? s - t + moder : s - t;
                    w = 1ll * w * unit % moder;
                }
            }
        }
        if (type == 1) return;
        int inv = powermod(length, moder - 2, moder);
        for (int i = 0; i < length; ++ i){
            a[i] = 1ll * a[i] * inv % moder;
        }
    }

    void mult(biginteger &q){
        static int aux[1 << max];
        if (!sig || !q.sig) return clear();
        int n = length + q.length;
        int lengthans = 1;
        for ( ; lengthans < n; lengthans <<= 1)
            ;
        memcpy(aux, q.a, sizeof(int) * lengthans);
        ntt(a, lengthans, 1);
        ntt(aux, lengthans, 1);
        for (int i = 0; i < lengthans; i++){
            a[i] = 1ll * a[i] * aux[i] % moder;
        }
        ntt(a, lengthans, -1);
        for (int i = 0; i < n - 1; i++){
            a[i + 1] += a[i] / 10;
            a[i] %= 10;
        }
        length = n;
        for ( ; length && !a[length - 1]; -- length)
            ;
        sig *= q.sig;
    }

    void mult(ll q){
        if (!q || !sig) return clear();
        ll x = std::abs(q), remain = 0;
        for (ll i = 0; i < length; ++ i){
            remain += a[i] * x;
            a[i] = remain % 10;
            remain /= 10;
        }
        a[length] = remain;
        for ( ; a[length]; ++ length){
            a[length + 1] = a[length] / 10;
            a[length] %= 10;
        }
        for ( ; length && !a[length - 1]; -- length)
            ;
        sig *= q < 0 ? -1 : 1;
    }

    // ??·?ê±power±è?±?ó3??y
    void power(int exp){
        static biginteger aux;
        if (!sig) return;
        aux.assign <int>(1);
        for ( ; exp; exp >>= 1){
            if (exp & 1){
                aux.mult(*this);
            }
            aux.mult(aux);
        }
        assign(aux);
    }

    void divide(biginteger &q){
        static biginteger aux, aux1;
        if (!sig || !q.sig)    return;
        if (length < q.length) return clear();
        bool neg1 = sig == 1, neg2 = q.sig == 1;
        abs(), q.abs();
        int num = 0;
        for (int i = q.length - 1; i >= q.length - 3; -- i){
            (num *= 10) += i >= 0 ? q.a[i] : 0;
        }
        num = 100000 / num;
        int nowprecision = 1;
        aux.assign <int>(num);
        for ( ; nowprecision <= length - q.length; nowprecision <<= 1){
            aux1.clear();
            aux1.length = (nowprecision << 1) + 3, aux1.sig = 1;
            for (int i = q.length - aux1.length; i < q.length; ++ i){
                aux1.a[i - q.length + aux1.length] = i >= 0 ? q.a[i] : 0;
            }
            aux1.mult(aux), aux1.rightshift(nowprecision + 2);
            aux1.mult(aux),    aux1.rightshift(nowprecision + 2);
            aux.mult(2);
            aux.leftshift(nowprecision);
            aux.minus(aux1);
        }
        aux.mult(*this);
        aux.rightshift(q.length + nowprecision + 1);
        aux1.assign(aux);
        aux1.mult(q);
        minus(aux1);
        int flag = absgreaterequal(q) ? 2 : sig < 0 ? 1 : 0;
        assign(aux);
        if (flag){
            flag == 1 ? minusone() : addone();
        }
        if (!neg2){
            q.neg();
        }
        sig *= neg1 ^ neg2 ? -1 : 1;
    }

    ll divide(ll q){
        if (!sig || !q)    return 0;
        ll remain = 0, x = std::abs(q);
        for (int i = length - 1; i >= 0; -- i){
            remain = remain * 10 + a[i];
            a[i] = remain / x;
            remain %= x;
        }
        for ( ; length && !a[length - 1]; -- length);
        remain *= sig;
        sig *= q < 0 ? -1 : 1;
        if (!length){
            sig = 0;
        }
        return remain;
    }

    void sqrt(){
        static biginteger aux, aux1, aux2;
        if (sig <= 0) return;
        int num = 0;
        for (int i = length - 1; i >= length - 8; -- i){
            (num *= 10) += i >= 0 ? a[i] : 0;
        }
        ll x = length & 1 ? 10000000000000ll : 100000000000000ll;
        num = std::sqrt(1.0 * x / num);
        int nowprecision = 2;
        aux.assign <int>(num);
        for ( ; nowprecision <= (length >> 1) + 1; nowprecision = (nowprecision << 1) - 1){
            aux1.clear(), aux2.clear();
            aux1.length = (nowprecision << 1) + 1 + (length & 1), aux1.sig = 1;
            for (int i = length - aux1.length; i < length; ++ i){
                aux1.a[i - length + aux1.length] = i >= 0 ? a[i] : 0;
            }
            aux1.mult(aux), aux1.rightshift(nowprecision + 1);
            aux1.mult(aux),    aux1.rightshift(nowprecision + 1);
            aux1.divide(2);
            aux2.length = nowprecision + 1 << 1, aux2.sig = 1;
            aux2.a[aux2.length - 1] = 1, aux2.a[aux2.length - 2] = 5;
            aux2.minus(aux1);
            aux.mult(aux2);
            aux.rightshift(nowprecision + 2);
        }
        aux.mult(*this);
        aux.rightshift((length >> 1) + nowprecision + 1);
        aux1.assign(aux);
        aux1.mult(aux1);
        aux2.assign(*this);
        aux2.mult(2);
        minus(aux1);
        int flag = greater(aux2) ? 2 : sig < 0 ? 1 : 0;
        assign(aux);
        if (flag){
            flag == 1 ? minusone() : addone();
        }
    }
};

ll f(ll a,ll b,ll c){


    biginteger temp1,temp2;
    temp1.assign2(a);
    temp2.assign2(b);
    //temp.print();
    temp1.mult(temp2);
    a=temp1.divide(c);
    //cout<<"a=="<<a<<endl;
    //if(a<0) { cout<<"a="<<a<<" a<0"<<endl;a+=c; }
    // a = temp.tointeger();
    return a;
}

ll powermod2(ll a, ll exp, ll moder){
    a=a%moder;
    ll ret = 1;
    for ( ; exp!=0; exp >>= 1){
        if (exp & 1){
            //ret = 1ll * ret * a % moder;
            ret=f(a,ret,moder);
        }
        a=f(a,a,moder);
        //a = 1ll * a * a % moder;


    }
    return ret;
}



int T;
int main(){

    ios::sync_with_stdio(false);
    //freopen("local.in","r",stdin);

        // biginteger temp;
        // temp.assign2(9);
        // //temp.print();
        // temp.mult(7);
        // int t=temp.divide(5);
        // cout<<"temp: ";
        // temp.print();
        // cout<<endl;
        // cout<<"a: "<<t<<endl;

    while(cin>>T){
        fori(i,1,T){
            ll a,b,c;
            cin>>a>>b>>c;


            cout<<powermod2(a,b,c)<<endl;
        }
    }
    // c.assign(a);
    // a.divide(b);
    // a.print();
    // putchar('\n');
    // a.mult(b);
    // c.minus(a);
    // c.print();
    // putchar('\n');
    return 0;
}
View Code

方法二 快速乘解决中间的溢出问题
快速乘和快速幂类似,因为a*b%c可以理解为b个a相加后取模,即b次加法运算。对于加法运算,将b次加法按照b的二进制表示进行log(b)级别的加法计算是等价的。
例如11次加法,可以拆成1+2+0+8次加法运算,因此可以用类似快速幂的思想计算。 参考博客:https://blog.csdn.net/m0_37579232/article/details/88382947
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cmath>
#include <bitset>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <algorithm>
using namespace std;

typedef long long  ll;
#define mem(a, x) memset(a, x, sizeof a)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
#define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))

 
ll f(ll a,ll b,ll p){//a*b%p
    ll res=0;
    while(b){
        if(b&1)res=(res+a)%p;
        b>>=1;
        a=(a+a)%p;
    }
    return res;
}


ll powermod2(ll a, ll exp, ll moder){
    a=a%moder;
    ll ret = 1;
    for ( ; exp!=0; exp >>= 1){
        if (exp & 1){
            //ret = 1ll * ret * a % moder;
            ret=f(a,ret,moder);
        }
        a=f(a,a,moder);
        //a = 1ll * a * a % moder;


    }
    return ret;
}



int T;
int main(){

    ios::sync_with_stdio(false);
    //freopen("local.in","r",stdin);

        // biginteger temp;
        // temp.assign2(9);
        // //temp.print();
        // temp.mult(7);
        // int t=temp.divide(5);
        // cout<<"temp: ";
        // temp.print();
        // cout<<endl;
        // cout<<"a: "<<t<<endl;

    while(cin>>T){
        fori(i,1,T){
            ll a,b,c;
            cin>>a>>b>>c;


            cout<<powermod2(a,b,c)<<endl;
        }
    }
    // c.assign(a);
    // a.divide(b);
    // a.print();
    // putchar('\n');
    // a.mult(b);
    // c.minus(a);
    // c.print();
    // putchar('\n');
    return 0;
}
View Code

 方法三  平台支持不稳定的 __int128类型

  如果可以用这种类型的话可以直接替换爆精度的位置就可以。

  这种数据类型的使用注意事项: 

C++ 关于int128在何种环境下能够使用

关于__int128

猜你喜欢

转载自www.cnblogs.com/paulzjt/p/10526147.html