http://codeforces.com/contest/932/problem/E
看了很多大神们的博客后,自己总结了了一下自己的想法,理了理自己的思路。
题意就是求∑C(n,r)*rk的值,n很大,用常规方法做肯定TLE。
对于这个式子我们能联想到的就是二项式的展开式ƒ(x)=(1+x)n=∑C(n,r)*xr;
对f(x)求导在乘上X就变成了 x*ƒ‘(x)=nx*(1+x)n-1=∑C(n,r)*r*xr,(对其求导可以
把r提出了,k次操作就刚好出现所需要的式子)对这个操作进行k次就变成了∑C(n,r)*rk*xr,
令x=1就是我们要求的表达式了,右边的等式已经处理完了,左边的等式应该怎么处理呢!
x*ƒ‘(x)=nx*(1+x)n-1=∑C(n,r)*r*xr;进行了一次操作,还剩k-1次操作
x*(x*ƒ‘(x))'=nx*(1+x)n-1+n*(n-1)*x2*(1+x)n-2=∑C(n,r)*r2*xr;进行了两次操作,还剩k-2次操作
.......
令g(s,p,q)=xp*(1+x)q;表示还剩s次操作达到目标值,
x*g(s,p,q)'=p*xp*(1+x)q+q*xp+1*(1+x)q-1;dp[s][p][q]表示还剩s操作,式子为xp*(1+x)q的值,
<=>dp[s][p][q]=p*dp[s-1][p][q]+q*dp[p+1][q-1];进行了一次操作,还剩下s-1次操作.
到此dp的状态转移方程就找出来了,值得注意的是p+q=n,因此dp就可以开成二维数组了dp[s][p],
为什么用dp[s][p]而不使用q呢,主要是在于q是从n开始减小k,而n非常的大,数组不能存储,s与p
分别是从k、0开始变化的.
以上为我自己的总结的想法。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxk=5005; 4 const int mod=1e9+7; 5 int n,k; 6 int dp[maxk][maxk]; 7 long long Q_pow(int x,int n) 8 { 9 long long ans=1; 10 long long t=(long long )x; 11 ///这里使用long long是为了防止t*t超int了 12 ///不使用在第6组测试的时候会出错/ 13 while(n) 14 { 15 if(n%2==1) 16 ans=ans*t%mod; 17 t=t*t%mod; 18 n=n/2; 19 } 20 return ans%mod; 21 } 22 23 long long dfs(int s,int p,int q) 24 { 25 if(dp[s][p]!=-1) 26 return dp[s][p]; 27 long long cnt; 28 if(s==0) 29 cnt=Q_pow(2,q); 30 else if(q==0) 31 cnt=Q_pow(p,s); 32 else 33 cnt=p*dfs(s-1,p,q)+q*dfs(s-1,p+1,q-1); 34 return dp[s][p]=cnt%mod; 35 } 36 int main() 37 { 38 while(scanf("%d %d",&n,&k)!=EOF) 39 { 40 memset(dp,-1,sizeof(dp)); 41 long long ans=dfs(k,0,n); 42 printf("%lld\n",ans); 43 } 44 return 0; 45 }
当时肯定是没有做出这道题的,看见这道题也根本没有往二项式方面去想。。。。
大牛们果然还是大神啊。。。。