瞎JB推式子
ans=nk+∑i=1n−12n−1−iik=nk+2n−1∑i=1n−1(12)iik
令 R=12
ans=nk+2n−1∑i=1n−1Riik
令 f(n,k)=∑ni=1Riik
f(n+1,k)=f(n,k)$+Rn+1(n+1)k
f(2n,k)=f(n,k)+∑i=1nRn+i(n+i)k
=f(n,k)+Rn∑i=1nRi∑j=0k(kj)nk−jij
=f(n,k)+Rn∑j=0k(kj)nk−j∑i=1nRiij
=f(n,k)+Rn∑j=0k(kj)nk−j∑i=1nf(n,j)
这样就可以倍增做了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int P=1e9+7,R=(P+1)>>1;
inline int Pow(ll x,ll y){
int ret=1; x%=P;
for(;y;y>>=1,x=x*x%P) if(y&1) ret=ret*x%P;
return ret;
}
typedef pair<ll,int> par;
map<par,int> M;
int fac[25],inv[25];
inline int C(int x,int y){
return 1LL*fac[x]*inv[y]%P*inv[x-y]%P;
}
int f(ll n,int k){
if(n==0) return 0;
if(n==1) return R;
if(M.count(par(n,k))) return M[par(n,k)];
if(n&1){
int ret=f(n-1,k);
ret=(ret+1LL*Pow(R,n)*Pow(n,k))%P;
return M[par(n,k)]=ret;
}
int ret=f(n>>=1,k),cur=0;
for(int j=0;j<=k;j++)
cur=(cur+1LL*C(k,j)*Pow(n,k-j)%P*f(n,j))%P;
ret=(ret+1LL*cur*Pow(R,n))%P;
return M[par(n<<1,k)]=ret;
}
inline void Pre(){
fac[0]=1; for(int i=1;i<=20;i++) fac[i]=1LL*fac[i-1]*i%P;
inv[1]=1; for(int i=2;i<=20;i++) inv[i]=1LL*(P-P/i)*inv[P%i]%P;
inv[0]=1; for(int i=1;i<=20;i++) inv[i]=1LL*inv[i]*inv[i-1]%P;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
ll n; int k; Pre();
scanf("%lld %d",&n,&k);
int ans=(Pow(n,k)+1LL*Pow(2,n-1)*f(n-1,k))%P;
printf("%d\n",ans);
return 0;
}