【单峰计数DP】Problem F – Fabricating Sculptures

【单峰计数DP】Problem F – Fabricating Sculptures

image

题意:

你拥有m块正方体积木,在最底层铺上s块正方体积木,且在这个基础上,将其余m-s块积木铺好,且不能出现“凹”字的形状。

求问有多少种拼法?

设f[i,j]为最底层铺上i块,在其上方再铺j块的方案数。

(f[i,j]=1 imes f[i,j-i] + 2 imes f[i-1,j-(i-1)] +3 imes f[i-2,j-(i-2)]+....+i imes 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;
}

原文地址:https://www.cnblogs.com/BeautifulWater/p/15477383.html