集训营第二次考欧拉降幂了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; }