链接:牛客网
题目
The Barefooted Acrobatics People’s Club wants to make a group photo in an original way. For the photo, they want to make a human pyramid, where each person rests on the ground or rests on the shoulders of two people below him or her.
Making a human pyramid demands a lot from the acrobats involved, so the club selected a group consisting of strong people of which they are assured that these people can carry enough weight. The others are ‘agile’ and to make sure everyone is comfortable during the photo, there can only be agile people directly above an agile person.
The photographer wants to make a photo of a pyramid with h people on the flfloor, h−1 on the second layer, h−2 on the third layer, and so on, with a single person on the hth layer. You have s strong people at your disposal, and the other h(h + 1) − s people are agile. What is the number of ways you can arrange the pyramid satisfying the demands of the photographer? Since this number may be large, you should fifind it modulo 109 + 7.
Two pyramids P1 and P2 are difffferent if there exists a location where P1 has an agile person and P2 a strong person, or vice versa.
输入描述:
The input consists of:
A line containing two integers h (1 ≤ h ≤ 100) and s (0 ≤ s ≤ h(h + 1)), the number of layers in the pyramid and the number of strong people.
输出描述:
Output the number of possible ways to build a pyramid with the given constraints, modulo109 + 7.
示例1
输入
3 3
输出
3
示例2
输入
5 3
输出
14
题意
由人搭起一个人型金字塔,人分为两种,一种是普通人(用N表示),一种是强壮的人(用S表示),S只能站立在地面上或者站在同为S的人上面(即P要么在地面,要么左右侧均有S),给定你金字塔的高度,S的数量,求能够构成的金字塔的种数。
思路
单纯的暴力显然是会T的,考虑用dp解决。
我们可以观察到一个S要么在地面,要么需要左右两侧S的支撑,如果我们从斜对角的方向观察题目,思路就更加清晰了
如果第i行对角线有j(j>1)个S的话,那么这j个S必定处于对角线底部连续,且其前一行至少有j-1个S以对其进行支撑
另一种情况就是第i行只有1个S,S站在地面上
dp
我们定义dp数组的含义如下
后面定义的最后一行都指斜对角线最后一行(以左上至右下,从左至右标号)
转移方程为
dp[i][j][k]=dp[i][j][k+1](1)+dp[i-1][j-k][k-1] (2)
解释:
最后一行至少使用k个S有两种可能:
1.最后一行至少使用k+1个S
2.最后一行正好使用k个S
第二种可能:
如果要让最后一行能够正好有k个人,那么其前一行需要至少有k-1个人,且从第1行至倒数第二行总共有j-k个S
代码
#include <iostream>
#define ll long long
#define f(x,y,z) for(int x=(y),_=(z);x<_;x++)
using namespace std;
ll dp[100+10][5000+300][100+10];
const int modn=1e9+7;
void solve() {
int h,s;
cin >> h >> s;
f(i,0,h) {
f(j,0,h) {
dp[i][0][j]=0;
}
}
f(i,1,h+1) {
f(j,1,s+1) {
for(int k=min(i,j);k>=0;k--) {
if(j==0) {
continue;
}
if(k==0) {
dp[i][j][k]=(dp[i][j][k+1]+dp[i-1][j-k][0])%modn;
continue;
}
if(k==j) {
if(j==1) {
dp[i][j][k]=1;
}
else {
dp[i][j][k]=0;
}
continue;
}
dp[i][j][k]=(dp[i][j][k+1]+dp[i-1][j-k][k-1])%modn;
}
}
}
printf("%lld\n",max(dp[h][s][0],1LL));
}
int main(void) {
solve();
}