XJOI1657&Codevs1255搭积木【树状动规】

搭积木

一种积木搭建方式,高为H的积木,最底层有M个积木,每一层的积木数是他的低一层的积木数+1或-1。总共有N个积木。(且每行积木数不超过10)

比如上图N=13 H=6 M=2。

输入格式:

第一行为三个整数、N、H、M。
第二行以后每行一个整数K,-1为结束符。

输出格式:

第一行为满足N、H、M的积木搭建方案总数(1<=N<=540 H<=60 M<=10)
以后每一行对于对应的K,给出顺序排列的第K种方案(最小的排列为第一种)。

样例输入:

13 6 2
1
3
-1

样例输出:

3
2 1 2 3 2 3
2 3 2 3 2 1

时间限制:

1000

初次看这题竟不易想到树状动规,毕竟输出路径实在太容易想到暴搜了,但是事实证明动规是对的

f[i][j][k]是指堆到第i层,第i层堆j个,共用了k个

f[i][j][k]=f[i-1][j-1][k-j]+f[i-1][j+1][k-j]

边界:f[1][i][i]=1;

路径打印:若x大于f[i][j-1][k-i],则x-=f[i][j-1][k-i],打出当前搜索到的行,然后下一层搜索

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 int n,h,m;
 6 long long f[61][11][541],qst;
 7 inline void work(long long x,int h,int now,int a)
 8 {
 9     printf("%d ",now);
10     if(h==1) return;
11     a-=now;
12     if(x>f[h-1][now-1][a])
13     {
14         x-=f[h-1][now-1][a];
15         now++;
16     }
17     else now--;
18     work(x,h-1,now,a);
19     return;
20 }
21 int main()
22 {
23     scanf("%d%d%d",&n,&h,&m);
24     for(int i=1;i<=min(h+m-1,10);i++) f[1][i][i]=1;
25     for(int i=2;i<=h;i++)
26         for(int j=1;j<=min(h+m-1,10);j++)
27             for(int k=1;k<=n;k++) f[i][j][k]=f[i-1][j-1][k-j]+f[i-1][j+1][k-j];
28     printf("%lld",f[h][m][n]);
29     while(1)
30     {
31         scanf("%lld",&qst);
32         if(qst==-1) break;
33         printf("\n");
34         work(qst,h,m,n);
35     }
36     return 0;
37 }
时间: 2024-08-26 05:52:55

XJOI1657&Codevs1255搭积木【树状动规】的相关文章

codvs 1163 访问艺术馆 树状动规

[问题描述] 经过数月的精心准备,Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动.艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室.Peer知道每个展室里藏画的数量,并且他精确测量了通过每条走廊的时间.由于经验老到,他拿下一幅画需要5秒的时间.你的任务是编一个程序,计算在警察赶来前 ,他最多能偷到多少幅画. [输入格式] 第1行是警察赶到的时间,以秒为单位.第2行描述了艺术馆的结构,是一串非负整数,成对地出现:每一对的第一个数是走过一条走廊的时间,第2个数是它

【bzoj1109】[POI2007]堆积木Klo 动态规划+树状数组

题目描述 Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置.请你告诉Mary她应该移走哪些积木. 输入 第一行为一个数n,表示高塔的初始高度.第二行包含n个数a1,a2,...,an,表示从下到上每个积木上面的数. 输出 注意:请

codevs 1255 搭积木 x

1255 搭积木 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 一种积木搭建方式,高为H的积木,最底层有M个积木,每一层的积木数是他的低一层的积木数+1或-1.总共有N个积木.(且每行积木数不超过10) 比如下图N=13 H=6 M=2. 输入描述 Input Description 第一行为三个整数.N.H.M. 第二行以后每行一个整数K,-1为结束符. 输出描述 Output Description 第一行为满足N.H

代码与算法集锦-归并排序+树状数组+快排+深度优先搜索+01背包(动态规划)

归并排序 求逆序数 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 首先考虑下如何将将二个有序数列合并.这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数.然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可. //将有序数组a[]和b[]合并到c[]中 void MemeryArray(int a[], int n, int b[], int m, int c

[BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

4785: [Zjoi2017]树状数组 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 297  Solved: 195[Submit][Status][Discuss] Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道 基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1)

树状数组求逆序对:POJ 2299、3067

前几天开始看树状数组了,然后开始找题来刷. 首先是 POJ 2299 Ultra-QuickSort: http://poj.org/problem?id=2299 这题是指给你一个无序序列,只能交换相邻的两数使它有序,要你求出交换的次数.实质上就是求逆序对,网上有很多人说它的原理是冒泡排序,可以用归并排序来求出,但我一时间想不出它是如何和归并排序搭上边的(当初排序没学好啊~),只好用刚学过的树状数组来解决了.在POJ 1990中学到了如何在实际中应用上树状数组,没错,就是用个特殊的数组来记录即

POJ 1990 MooFest 树状数组

这题是我看了大白书树状数组后刷的第一道题,确实难度不小,所以只好上网找题解了,网上的做法确实精彩.这题的题意主要是有N头牛,每两头牛之间交流的费用为它们的距离乘上两者音量的最大值(即max(v(i),v(j))),然后统计所有牛两两交流的总费用.一开始能想到的做法便是O(n2)的暴力枚举了,当时的我也只能想到这样的复杂度,很纳闷怎么能和树状数组搭上边呢?然后看了别人的题解后才惊叹其思路之妙. 在博客 http://www.cnblogs.com/Fatedayt/archive/2011/10/

【POJ3612】【USACO 2007 Nov Gold 】1.Telephone Wire 动规

题意: 给出若干棵树的高度,你可以进行一种操作:把某棵树增高h,花费为h*h. 操作完成后连线,两棵树间花费为高度差*定值c. 求两种花费加和最小值. 题解: 跟NOIP2014 D1T3很像. 暴力动规是O(1*10^9)会T 所以单调队列一下,每颗树扫两遍结束. 完事,看水代码吧. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N

树状DP入门

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 题目大意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少? 解题思路:树形DP入门题.由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优.其实不然,有可能父节点和子节点都不选,而要选子孙节点.不过只要再往深点想下,就可以得出动态规划的解法.每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那