传送门

题意:

给定n,k,求 nr=1Crnrk ∑ r = 1 n C n r r k

n<=1e9,k<=5e3 n <= 1 e 9 , k <= 5 e 3

Solution:

冥思苦想数论方式……..最后GG

题解让人眼前一亮:

定义函数 f(x)=(1+x)n=nr=0Crnxr f ( x ) = ( 1 + x ) n = ∑ r = 0 n C n r x r

那么我们对他求一次导: f(x)=n(1+x)n1=nr=1Crnrxr1 f ′ ( x ) = n ( 1 + x ) n − 1 = ∑ r = 1 n C n r r x r − 1

再把这个式子乘一个x: xf(x)=nx(1+x)n1=nr=1Crnrxr x f ′ ( x ) = n x ( 1 + x ) n − 1 = ∑ r = 1 n C n r r x r

然后我们发现:对于 f(x) f ( x ) ,题目所给的公式就是我们对它进行上面的操作(求导后乘x)k次后x=1的值

那么这道题现在就转化成关于 f(x) f ( x ) 的问题了

f[a][b][c] f [ a ] [ b ] [ c ] 是对 xb(1+x)c x b ( 1 + x ) c 做a次操作后x=1的值

那么最终的答案即为 f[k][0][n] f [ k ] [ 0 ] [ n ]

转移依据高中知识: f[a][b][c]=bf[a1][b][c]+cf[a1][b+1][c1] f [ a ] [ b ] [ c ] = b ∗ f [ a − 1 ] [ b ] [ c ] + c ∗ f [ a − 1 ] [ b + 1 ] [ c − 1 ]

a=0时, f[a][b][c]=2c f [ a ] [ b ] [ c ] = 2 c

进行记忆化搜索即可

虽然状态是三维的,但是因为b+c恒等于n,所以我们的复杂度实际上是 O(k2) O ( k 2 )

注意特判边界情况

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int f[5010][5010];
int n,k;
const int mod=1e9+7;
int fast_pow(int x,int a)
{
    int ans=1;
    for (;a;a>>=1,x=1ll*x*x%mod) if (a&1) ans=1ll*ans*x%mod;
    return ans;
}
int dp(int a,int b)
{
    if (b>n) return 0;
    if (f[a][b]>=0) return f[a][b];
    int c=n-b;
    if (a==0) {f[a][b]=fast_pow(2,c);return f[a][b];}
    f[a][b]=(1ll*b*dp(a-1,b)+1ll*c*dp(a-1,b+1))%mod;
    return f[a][b];
}
int main()
{
    scanf("%d%d",&n,&k);
    memset(f,-1,sizeof(f));
    printf("%d",dp(k,0));
}