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 }

 

posted @ 2018-01-10 10:52  Leohh  阅读(583)  评论(1编辑  收藏  举报