幂塔个位数的计算H ----2021牛客寒假算法基础集训营1 题解

在这里插入图片描述
题意: 输入字符串底数a 以及字符串n n代表有多少个a 爬楼梯一样的幂次,现在要我们求幂塔的个位是多少。我们来分析一下。

首先ab %p 当b很很大很大时
引用欧拉降幂(知识点,不会的朋友自行百度学习一下),把b的幂次降低下来,然后来求解,这里还涉及到另外一个知识点
欧拉函数φ
在这里插入图片描述

上述推导归纳起来就是三种情况,分情况计算多项式就OK了
多项式长度最多为1e5*7 吧 应该 NTT FFT都可
一直TLE 直到我把求降幂后的幂次以及g数组的初始化优化后才过)
fft 应该会跑的更快

/*#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")*/
#include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define LL long long
#define Re  int
using namespace std;
const int N=1097152+3,P=998244353,G=3;
int n,m,invn,invG,f[N],g[2000007],tr[N];
inline void in(Re &x)
{
    
    
    int f=0;
    x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int mi(Re x,Re k)
{
    
    
    Re s=1;
    while(k)
    {
    
    
        if(k&1)
            s=(LL)s*x%P;
        x=(LL)x*x%P,k>>=1;
    }
    return s;
}
inline int inv(Re x)
{
    
    
    return mi(x,P-2);
}
inline void NTT(Re *f,Re n,Re op)
{
    
    
    for(Re i=0; i<n; ++i)
        if(i<tr[i])
            swap(f[i],f[tr[i]]);
    for(Re p=2; p<=n; p<<=1)
    {
    
    
        Re len=p>>1,w1=mi(op?invG:G,(P-1)/p);
        for(Re st=0; st<n; st+=p)
            for(Re i=st,base=1; i<=st+len-1; ++i)
            {
    
    
                Re tmp=(LL)base*f[len+i]%P;
                f[len+i]=(f[i]-tmp+P)%P,(f[i]+=tmp)%=P,base=(LL)base*w1%P;
            }
    }
}
inline void times(Re *f,Re n,Re *g,Re m)
{
    
    
    for(m+=n,n=1; n<=m; n<<=1)
        ;
    invn=inv(n),invG=inv(G);
    for(Re i=1; i<n; ++i)
        tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
    NTT(f,n,0),NTT(g,n,0);
    for(Re i=0; i<n; ++i)
    {
    
    
        f[i]=(LL)f[i]*g[i]%P;
        g[i]=0;
    }
    NTT(f,n,1);
    for(Re i=0; i<=m; ++i)
        f[i]=(LL)f[i]*invn%P;
}
long long euler(long long x)  //直接求欧拉函数 //还有一种线性筛法
{
    
    
    long long res=1;
    for(long long i=2; i*i<=x; ++i)
    {
    
    
        if(x%i==0)
        {
    
    
            x/=i;
            res*=(i-1);
            while(x%i==0)
            {
    
    
                x/=i;
                res*=i;
            }
        }
    }
    if(x>1)
        res*=(x-1);
    return res;
}
string lcj_1;
string lcj_2;

signed main()
{
    
    

    IOS;
    cin>>lcj_1;
    cin>>lcj_2;
    n=lcj_1.size()-1; //a
    m=lcj_2.size()-1; //  n
    ll ph=euler(10);
    ll pph=euler(ph);
    if(m==0&&(lcj_2[m]-'0')<=2)
    {
    
    
        if(lcj_2[m]-'0'==1)
        {
    
    
            cout<<lcj_1[n];
            return 0;
        }

        ll cou_num=0;
        int ff=0;

        for(int i=0; i<=n; ++i)
        {
    
    

            cou_num=(cou_num*10+(lcj_1[i]-'0'));
            if(cou_num>=ph)
            {
    
    
                ff=1;
                cou_num%=ph;
            }
        }  // 对 n  降幂

        if(ff)
        {
    
    
            cou_num+=ph;
        }

        ll chang_f=n;
        for(Re i=0; i<=n; ++i)
        {
    
    
            f[i]=lcj_1[n-i]-'0';
        }


        while(cou_num>=2)
        {
    
    

            for(Re i=0; i<=n; ++i)
            {
    
    

                g[i]=lcj_1[n-i]-'0';
            }

            times(f,chang_f,g,n); //  一次FFT
            for (int i=0; i<chang_f+n+5; i++)
            {
    
    
                if (f[i]>=10)
                {
    
    
                    f[i+1]+=f[i]/10;
                    f[i]%=10;
                }
            }
            int tail=chang_f+n+5;
            while (f[tail]==0 && tail>0)
                tail--;
            while (f[tail]>=10)
            {
    
    
                f[tail+1]+=f[tail]/10;
                f[tail++]%=10;
            }
            chang_f=tail;
            cou_num--;
        }
        cout<<f[0];
        return 0;
    }

    int numn=0;

    if((lcj_1[n]-'0')%2==0)
    {
    
    
        numn=2;
    }
    else
    {
    
    
        numn=3;
    }
    ll chang_f=n;
    for(Re i=0; i<=n; ++i)
    {
    
    
        f[i]=lcj_1[n-i]-'0';
    }
    while(numn>=2)
    {
    
    
        for(Re i=0; i<=n; i++)
        {
    
    

            g[i]=lcj_1[n-i]-'0';
        }

        times(f,chang_f,g,n); //  一次FFT
        for (int i=0; i<chang_f+n+5; i++)
        {
    
    
            if (f[i]>=10)
            {
    
    
                f[i+1]+=f[i]/10;
                f[i]%=10;
            }
        }
        int tail=chang_f+n+5;
        while (f[tail]==0 && tail>0)
            tail--;
        while (f[tail]>=10)
        {
    
    
            f[tail+1]+=f[tail]/10;
            f[tail++]%=10;
        }
        chang_f=tail;


        numn--;
    }
    ll numnn_2=0;

    numnn_2=f[0];
    if(chang_f>0)
    {
    
    
        numnn_2=numnn_2+f[1]*10;
    }
    numnn_2=numnn_2%4+4;
    memset(f,0,sizeof(f));
    ll chang_ff=n;
    for(Re i=0; i<=n; ++i)
    {
    
    
        f[i]=lcj_1[n-i]-'0';
    }
    while(numnn_2>=2)
    {
    
    
        for(Re i=0; i<=n; i++)
            g[i]=lcj_1[n-i]-'0';

        times(f,chang_ff,g,n);
        for (int i=0; i<n+chang_ff+5; i++)
        {
    
    
            if (f[i]>=10)
            {
    
    
                f[i+1]+=f[i]/10;
                f[i]%=10;
            }
        }
        int tail=n+chang_ff+5;
        while (f[tail]==0 && tail>0)
            tail--;
        while (f[tail]>=10)
        {
    
    
            f[tail+1]+=f[tail]/10;
            f[tail++]%=10;
        }
        chang_ff=tail;

        numnn_2--;
    }

    cout<<f[0];

    return 0;

}


猜你喜欢

转载自blog.csdn.net/weixin_45948940/article/details/113555472