Gym102428F Fabricating Sculptures(DP+前缀和)

Gym102428F Fabricating Sculptures(DP+前缀和)

Description
Miguel Angelo is a great sculptor, widely recognized for his outdoor sculptures. In his hometown, it is very common to find one of his creations in squares and gardens. People love his sculptures, not only for their beauty, but also because they look like new even after decades.The sculptures do not degrade easily due to the material and technique developed by Miguel and his staff over the years.
To build the sculptures, he first constructs its base by stacking blocks of waterproof plaster(his secret material), forming several stacks of blocks in a straight line. He always uses identical blocks, and each stack has at least one block. To stabilize the structure, he surrounds it by two big glass panes, one behind the stacks and one in front of them. Then he waits for the rain for as long as it takes. If the structure is such that it doesn’t accumulate water during this procedure, Miguel is sure that the base can be used to obtain a piece of long-lasting artwork.Notice that water will accumulate on a block if there are obstacles (other blocks) on both sides(to the left and to the right).
The following picture shows the front view of several different bases. All of them consist of three stacks made of a total of six blocks, with each stack having at least one block as required.However, the eight bases on the left will lead to long-lasting artwork, while the two bases on the right will not.
Gym102428F Fabricating Sculptures(DP+前缀和)_第1张图片
Miguel Angelo is receiving a lot of sculpture requests. Although he has all the freedom to create the artwork, he wants to be fair and use the same number of stacks and the same number blocks in each of the sculptures. Since he doesn’t want to sell identical sculptures to different clients, he will construct a different base each time.
He worries that he won’t be able to fulfill all the requests. Help him calculate the number of different bases given the number of stacks and the number of blocks that the base must have.
Input
The input consists of a single line that contains two integers S and B (1 ≤ S ≤ B ≤ 5000)indicating respectively the number of stacks and the number of blocks that the base must have.
Output
Output a single line with an integer indicating the number of different bases that don’t accumulate water which Miguel can construct. Because this number can be very large, output the remainder of dividing it by 1e9 + 7.
Sample Input
3 6
Sample Output
8
Sample Input 2
3 7
Sample Output 2
12

题意

b b b个方块来堆叠,要求底座一定 s s s个方块,问不摆出凹槽(能储水)的情况有几种。

题解

d p [ i ] [ j ] dp[i][j] dp[i][j]为底座有i个方块时上面还有j个方块可以摆放。
状态转移方程为:
j − i > i j - i > i ji>i时状态转移方程为:
dp[i][j] = s * dp[1][j - 1] + (i - 1) * dp[2][j - 2] + ... + dp[i][j - i]
j − i < = i j - i <= i ji<=i时状态转移方程为:
dp[i][j] = i * dp[1][j - 1] + (i - 1) * dp[2][j - 2] + ... + (i - j + 1) * dp[j][0]
其实从这里可以看出,如果用这种写法,那复杂度相当高,肯定过不了。因此需要使用前缀和来简化这个状态转移方程。
苏学长的帮助下想了很久,终于把 p r e pre pre数组和 s u m sum sum数组给看懂了。
s u m [ j ] sum[j] sum[j]表示用了 j j j个方块的情况个数。
p r e pre pre数组就比较难以理解。它的意思我就打个比方来解释一下。假设 i = = 3 i==3 i==3,那么 p r e [ j ] pre[j] pre[j]就是 d p [ 3 ] [ j ] dp[3][j] dp[3][j]
画个图解释一下:
Gym102428F Fabricating Sculptures(DP+前缀和)_第2张图片

其余内容均写入代码中的注释。这道题由于我水平不足实在有点难以讲透彻,可以看代码再仔细想想。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ((x) & -(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e6 + 10, NN = 5e3 + 10, INF = 0x3f3f3f3f, LEN = 20;
const ll MOD = 1e9 + 7;
const ull seed = 31;
inline int read() {
     
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
     
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
     
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
int s, b;
int sum[NN], pre[NN];
int dp[NN][NN];  // dp[i][j]表示底座有i个方块时上面还有j个方块可以摆放
void init() {
     }
int main() {
     
    scanf("%d%d", &s, &b);
    b -= s;
    for (int i = 1; i <= s; i++) {
     
        for (int j = 0; j <= b; j++) {
     
            pre[j] =
                (pre[j] + sum[j]) %
                MOD;  //将当先发现的j个方块的排列个数也就是sum[j]加入pre[j]中,省略状态转移方程中的重复运算
            if (j == 0)
                dp[i][j] = 1;
            else
                dp[i][j] = pre[j];
            sum[i + j] = (sum[i + j] + dp[i][j]) % MOD;
        }
    }
    printf("%d\n", dp[s][b]);
    return 0;
}

你可能感兴趣的:(前缀和,DP,C++)