补了一发伯努利数求自然数幂和,感觉挺好玩的...
具体数学上没有给构造,伯努利牛逼!真的不知道这个东西怎么“凭经验发现”
首先定义伯努利数$B_n$:$\sum\limits_{j=0}^m\binom{m+1}jB_j=[m=0]$
自然数幂求和$S_m(n)=\sum\limits_{k=0}^{n-1}k^m$
$S_{m+1}(n)+n^{m+1}=\sum\limits_{k=0}^{n-1}(k+1)^{m+1}=\sum\limits_{k=0}^{n-1}\sum\limits_{j=0}^{m+1}\binom{m+1}jk^j=\sum\limits_{j=0}^{m+1}\binom{m+1}jS_j(n)$
即是说$n^{m+1}=\sum\limits_{j=0}^m\binom{m+1}jS_j(n)$
现在我们要证$S_m(n)=\frac1{m+1}\sum\limits_{k=0}^m\binom{m+1}kB_kn^{m+1-k}$(这是伯努利“凭经验发现”的==)
对$m$归纳,假设$0\cdots m-1$都成立,设$\Delta=S_m(n)-\frac1{m+1}\sum\limits_{k=0}^m\binom{m+1}kB_kn^{m+1-k}$
接下来会用到$\binom{n+1}{m+1}=\frac{n+1}{m+1}\binom nm$和$\binom rm\binom mk=\binom rk\binom{r-k}{m-k}$
$\begin{aligned}n^{m+1}&=\sum\limits_{j=0}^m\binom{m+1}jS_j(n)\\&=\binom{m+1}m\Delta+\sum\limits_{j=0}^m\binom{m+1}j\frac1{j+1}\sum\limits_{k=0}^j\binom{j+1}kB_kn^{j+1-k}\\&=(m+1)\Delta+\sum\limits_{j=0}^m\sum\limits_{k=0}^j\binom{m+1}j\binom{j+1}{j-k}\frac{B_{j-k}}{j+1}n^{k+1}&k'\gets j-k\\&=(m+1)\Delta+\sum\limits_{j=0}^m\sum\limits_{k=0}^j\binom{m+1}j\binom{j+1}{k+1}\frac{B_{j-k}}{j+1}n^{k+1}\\&=(m+1)\Delta+\sum\limits_{k=0}^m\frac{n^{k+1}}{k+1}\sum\limits_{j=k}^m\binom{m+1}j\binom jkB_{j-k}\\&=(m+1)\Delta+\sum\limits_{k=0}^m\frac{n^{k+1}}{k+1}\binom{m+1}k\sum\limits_{j=k}^m\binom{m+1-k}{j-k}B_{j-k}\\&=(m+1)\Delta+\sum\limits_{k=0}^m\frac{n^{k+1}}{k+1}\binom{m+1}k\sum\limits_{j=0}^{m-k}\binom{m-k+1}jB_j\\&=(m+1)\Delta+\sum\limits_{k=0}^m\frac{n^{k+1}}{k+1}\binom{m+1}k[m-k=0]\\&=n^{m+1}+(m+1)\Delta\end{aligned}$
这说明$\Delta=0$,命题得证
然后就是求伯努利数,对定义式$\sum\limits_{j=0}^m\binom{m+1}jB_j=[m=0]$做代换$n=m+1$,得到$\sum\limits_j\binom njB_j=B_n+[n=1]$
考虑它的指数型生成函数$B(z)$,对应到上式即为$e^zB(z)=B(z)+z$,也就是说$B(z)=\frac z{e^z-1}$,直接求逆就可以了
这个模数==要拆系数FFT,不过因为数据范围不大跑得还不算慢
#include<stdio.h> #include<math.h> #include<string.h> #include<algorithm> using namespace std; typedef long long ll; typedef double du; const int mod=1000000007; int mul(int a,int b){return a*(ll)b%mod;} int pow(int a,int b){ int s=1; while(b){ if(b&1)s=mul(s,a); a=mul(a,a); b>>=1; } return s; } struct comp{ du x,y; comp(du a=0,du b=0){x=a;y=b;} }; comp operator+(comp a,comp b){return comp(a.x+b.x,a.y+b.y);} comp operator-(comp a,comp b){return comp(a.x-b.x,a.y-b.y);} comp operator*(comp a,comp b){return comp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} int rev[131072],N; comp*w[17]; void pre(int n){ int i,j,k; for(N=1,k=0;N<n;N<<=1)k++; for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1)); for(i=2,k=0;i<=N;i<<=1,k++){ if(w[k]==0)w[k]=new comp[i>>1]; for(j=0;j<i>>1;j++)w[k][j]=comp(cos(j*M_PI/(i/2)),sin(j*M_PI/(i/2))); } } void fft(comp*a,int on){ int i,j,k,f; comp t; for(i=0;i<N;i++){ if(i<rev[i])swap(a[i],a[rev[i]]); } for(i=2,f=0;i<=N;i<<=1,f++){ for(j=0;j<N;j+=i){ for(k=0;k<i>>1;k++){ t=w[f][k]; t.y*=on; t=t*a[i/2+j+k]; a[i/2+j+k]=a[j+k]-t; a[j+k]=a[j+k]+t; } } } if(on==-1){ for(i=0;i<N;i++)a[i].x/=N; } } comp A[131072],B[131072],C[131072],D[131072]; void conv(int*a,int*b,int*c,int n){ int i; comp t; pre(n<<1); memset(A,0,N<<4); memset(B,0,N<<4); memset(C,0,N<<4); memset(D,0,N<<4); for(i=0;i<n;i++){ A[i]=a[i]>>15; B[i]=a[i]&32767; C[i]=b[i]>>15; D[i]=b[i]&32767; } fft(A,1); fft(B,1); fft(C,1); fft(D,1); for(i=0;i<N;i++){ t=A[i]*D[i]+B[i]*C[i]; A[i]=A[i]*C[i]; C[i]=B[i]*D[i]; B[i]=t; } fft(A,-1); fft(B,-1); fft(C,-1); for(i=0;i<n;i++)c[i]=((llround(A[i].x)%mod<<30)+(llround(B[i].x)%mod<<15)+llround(C[i].x)%mod)%mod; } int t1[65536]; void getinv(int*a,int*b,int n){ if(n==1){ b[0]=pow(a[0],mod-2); return; } int i; getinv(a,b,n>>1); conv(a,b,t1,n); for(i=0;i<n;i++)t1[i]=-t1[i]; (t1[0]+=2)%=mod; conv(t1,b,b,n); } int fac[65537],rfac[65537],a[65536],b[65536]; int ch(int n,int k){return mul(fac[n],mul(rfac[k],rfac[n-k]));} void getb(int n){ int i; fac[0]=1; for(i=1;i<=n;i++)fac[i]=mul(fac[i-1],i); rfac[n]=pow(fac[n],mod-2); for(i=n;i>0;i--)rfac[i-1]=mul(rfac[i],i); for(i=0;i<n;i++)a[i]=rfac[i+1]; getinv(a,b,n); for(i=0;i<n;i++)b[i]=mul(b[i],fac[i]); } void work(){ ll n; int m,i,s,t; scanf("%lld%d",&n,&m); n++; n%=mod; s=0; t=n; for(i=m;i>=0;i--){ (s+=mul(mul(ch(m+1,i),b[i]),t))%=mod; t=mul(t,n); } s=mul(s,pow(m+1,mod-2)); printf("%d\n",(s+mod)%mod); } int main(){ int T; getb(65536); scanf("%d",&T); while(T--)work(); }