Codeforces 478D Red-Green Towers:dp
题目链接:http://codeforces.com/problemset/problem/478/D
题意:
给你r个红方块和g个绿方块,让你用这些方块堆一个塔。
最高层有1个方块,每往下一层块数+1,同时要保证每层中的方块都是同一种颜色。
如图:
问你在塔的高度最高的前提下,堆出塔的方案数。
题解:
假设塔最高能堆d层,则:
d*(d+1)/2 <= r+g
解得:
d = floor((-1+sqrt(1+8*(r+g)))/2)
并且d最大不超过900。
表示状态:
dp[i][j] = numbers
表示已经堆了最上面的i层,用了j个红方块,此时的方法数。
找出答案:
ans = ∑ dp[d][max(0,d*(d+1)/2-g) to r]
因为最终还要保证用了绿方块的个数 <= g,所以枚举i至少要从d*(d+1)/2-g开始。
如何转移:
dp[i][j] = dp[i-1][j] + dp[i-1][j-i]
从上往下数第i层可能全用绿色,或全用红色
边界条件:
dp[0][0] = 1
另外要用滚动数组,否则会MLE。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 #define MAX_D 900 6 #define MAX_R 200005 7 #define MOD 1000000007 8 #define EPS 1e-5 9 10 using namespace std; 11 12 int r,g,d; 13 int dp[2][MAX_R]; 14 15 int main() 16 { 17 cin>>r>>g; 18 d=floor((-1.0+sqrt(1.0+8.0*(r+g))+EPS)/2.0); 19 memset(dp,0,sizeof(dp)); 20 dp[0][0]=1; 21 for(int i=1;i<=d;i++) 22 { 23 for(int j=0;j<=r;j++) 24 { 25 dp[i&1][j]=dp[(i-1)&1][j]; 26 if(j-i>=0) dp[i&1][j]+=dp[(i-1)&1][j-i]; 27 dp[i&1][j]%=MOD; 28 } 29 } 30 int ans=0; 31 for(int i=max(0,d*(d+1)/2-g);i<=r;i++) 32 { 33 ans=(ans+dp[d&1][i])%MOD; 34 } 35 cout<<ans<<endl; 36 }