zoukankan      html  css  js  c++  java
  • 【单峰计数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;
    }
    
    
  • 相关阅读:
    [TJOI2018]教科书般的亵渎
    luogu P4781 【模板】拉格朗日插值
    [SDOI2010]捉迷藏
    [CQOI2016]K远点对
    BZOJ4066 简单题
    [国家集训队]JZPFAR
    Understanding User and Kernel Mode
    Linux下如何查看系统启动时间和运行时间以及安装时间
    CentOS Linux搭建独立SVN Server全套流程(修改svn仓库地址、服务启动等)
    linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合:
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15477383.html
Copyright © 2011-2022 走看看