【单峰计数DP】Problem F – Fabricating Sculptures
【单峰计数DP】Problem F – Fabricating Sculptures
题意:
你拥有m块正方体积木,在最底层铺上s块正方体积木,且在这个基础上,将其余m-s块积木铺好,且不能出现“凹”字的形状。
求问有多少种拼法?
设f[i,j]为最底层铺上i块,在其上方再铺j块的方案数。
\(f[i,j]=1\times f[i,j-i] + 2\times f[i-1,j-(i-1)] +3\times f[i-2,j-(i-2)]+....+i\times f[1,j-1]\)
前面的系数代表可以摆放的位置数目。
单纯记忆化搜索的话,对于每一对i,j,也需要提取一大堆信息。
不妨写下dp数组
令i=1
dp[1][0]=1
dp[1][1]=1
dp[1][2]=1
dp[1][3]=1
.......
令i=2
dp[2][0]=1
dp[2][1]=2*dp[1][0]
dp[2][2]=2*dp[1][1]+dp[2][0]
dp[2][3]=2*dp[1][2]+dp[2][1]
.......
令i=3
dp[3][0]=1
dp[3][1]=3*dp[1][0]
dp[3][2]=3*dp[1][1]+2*dp[2][0]
dp[3][3]=3*dp[1][2]+2*dp[2][1]+dp[3][0]
....
我们可以发现对于每一dp[i][j]
是dp[i][j-i]
(如果有的话)、各种方块数为j的模型的最右端放置到新开辟的第i块的方案数和放在前i-i块的方案数的三种类型之和。
#include <bits/stdc++.h>
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define pi acos(-1.0)
#define PII pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
using namespace std;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
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*10+ch-'0',ch=getchar();
return x*f;
}
const int N = 5E3+100;
int dp[N][N],sum[2*N],pre[2*N],n,m;
int main()
{
n=read(),m=read();
m-=n;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
pre[j]=(pre[j]+sum[j])%MOD;
if(j==0) dp[i][0]=1;
else dp[i][j]=(dp[i][j]+pre[j])%MOD;
sum[i+j]=(sum[i+j]+dp[i][j])%MOD;
}
}
cout<<dp[n][m];
return 0;
}