集训营第二次考欧拉降幂了Orz
首先不管n,我们就算能选[1,m]的取值的时候的答案。和B题差不多的idea,我们能想到答案其实是,这是一个n+1次的多项式,如果说m很大的话,我们当然不能直接算,但是,我们可以利用拉格朗日插值法求出这个式的值。建议先学习下拉格朗日插值法。
之后,考虑的情况,我们当然不能直接算这个m,那么,题目给了模数,我们考虑只求m mod p的值,那么,考虑如何利用f(m mod p)求f(m).因为
为n+1次多项式,那么,我们设
,则,
,二项式定理展开后,发现
,因此,我们只需要求
。
对于,我们考虑欧拉降幂求即可。
这道题需要学的主要是欧拉降幂的写法,这里所用的EXP函数的方法,或者是官方题解中的预处理都是可以使用的方法,又或者是使用我第一场题解中的取对数的方法都是可行的。具体可以看下我的提交记录。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
void read(T&x){
x=0;
char ch=getchar();
int f=1;
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+(ch-'0');
ch=getchar();
}x*=f;
}
template<typename T>
void write(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
//===============================================================
#define int ll
#define MOD(x) (((x)%p+p)%p)
#define modit(a,b) ((a)>=(b)?(a)%(b)+(b):(a))
const int maxn=2e5+10;
int n,p;
int mul(int x,int y,int mod=::p){
return 1ll*x*y%p;
}
int add(int x,int y,int mod=::p){
return ((x+y)%p+p)%p;
}
ll ksm(ll a,ll n,ll p=::p){
ll res=1;
while(n){
if(n&1)res=res*a%p;
a=a*a%p;
n>>=1;
}
return res;
}
unordered_map<int,int>mp;
int phi(int x){
int bak=x;
if(mp.count(bak))return mp[bak];
int res=x;
for(int i=2;i*i<=x;++i){
if(x%i==0){
res=res-res/i;
while(x%i==0)x/=i;
}
}
if(x>1)res=res-res/x;
return mp[bak]=res;
}
int EXP(int a,int n,int p){
int res=1;
while(n){
if(n&1)res=modit(res*a,p);
a=modit(a*a,p);
n>>=1;
}
return res;
}
int ex_euler(int n,int mod){
if(mod==1)return 1;
return ksm(n,ex_euler(n,phi(mod))+phi(mod),mod);
}
int f[maxn];
int fac[maxn],finv[maxn];
void init(int f[]){
int lim=n+2;
for(int i=1;i<=lim;++i){
f[i]=MOD(f[i-1]+MOD(ksm(i,n+1)-i*ksm(i-1,n)));
}
fac[0]=1;
for(int i=1;i<min(p,maxn);++i)fac[i]=mul(fac[i-1],i);
finv[min(p-1,maxn-1)]=ksm(fac[min(p-1,maxn-1)],p-2,p);
for(int i=min(p-2,maxn-2);i>=0;--i)finv[i]=mul(finv[i+1],(i+1));
}
int pre[maxn],suf[maxn];
ll solve(int y[],int n,int x){
int lim=n+1;
if(x<=lim)return y[x];
pre[1]=1,suf[lim]=1;
for(int i=2;i<=lim;++i)pre[i]=pre[i-1]*(x-(i-1))%p,pre[i]=(pre[i]%p+p)%p;
for(int i=lim-1;i>=0;--i)suf[i]=suf[i+1]*(x-(i+1))%p,suf[i]=(suf[i]%p+p)%p;
int res=0;
for(int i=1;i<=lim;++i){
int sig=((lim-i)&1?(-1):1);
ll up=MOD(MOD(sig*suf[i]*pre[i])*f[i]);
ll down=MOD(finv[i-1]*finv[lim-i]);
res=(res+mul(up,down))%p;
res=(res%p+p)%p;
//res=add(res,MOD(sig*mul(mul(suf[i],pre[i]),mul(finv[i],finv[lim-i]))));
}
return res;
}
signed main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
read(n),read(p);
int m=ex_euler(n,p);
init(f);
int res=0;
cout<<solve(f,n+1,m)<<endl;
return 0;
}
京公网安备 11010502036488号