zoukankan      html  css  js  c++  java
  • 牛客小白月赛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('
    ');
        // a.mult(b);
        // c.minus(a);
        // c.print();
        // putchar('
    ');
        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('
    ');
        // a.mult(b);
        // c.minus(a);
        // c.print();
        // putchar('
    ');
        return 0;
    }
    View Code

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

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

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

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

    关于__int128

  • 相关阅读:
    cf1131f 构造+并查集
    多源最短路小结
    bzoj2200拓扑排序+最短路+联通块
    cf478d 线性dp好题
    cf919D 线性dp+拓扑排序
    hiho1460 rmq模板题
    最小标示法模板 poj1509
    JAVA动态代理机制分析guide
    java动态代理(JDK和cglib)
    AOP面向切面编程
  • 原文地址:https://www.cnblogs.com/paulzjt/p/10526147.html
Copyright © 2011-2022 走看看