题意: 输入字符串底数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;
}