LA 3637 - The Bookcase(DP)

题目链接:点击打开链接

思路:用d[i][j][k]表示前i个, 已经占据了第一层j厚度,第二层k厚度的最小高度。 转移即可。 这题卡常数挺恶心的, 要加点恶心的优化。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
// & 0x7FFFFFFF
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 77;
int T,n,m,d[maxn][maxn*30][maxn*30],sum[maxn];
struct node {
    int h, w;
    bool operator < (const node& rhs) const {
        return h > rhs.h;
    }
}a[maxn];
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        int maxw = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &a[i].h, &a[i].w);
            maxw += a[i].w;
        }
        sort(a+1, a+n+1);
        for(int i = 1; i <= n; i++) {
            sum[i] = sum[i-1] + a[i].w;
        }
        for(int i = 0; i <= n; i++) {
            for(int j = 0; j <= maxw/2; j++) {
                for(int k = 0; k <= maxw/2; k++) d[i][j][k] = INF;
            }
        }
        d[0][0][0] = 0;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j <= maxw/2; j++) {
                for(int k = 0; k <= maxw/2; k++) {
                    int& ans = d[i][j][k];
                    if(ans == INF) continue;
                    if(j == 0) d[i+1][j+a[i+1].w][k] = min(d[i+1][j+a[i+1].w][k], ans + a[i+1].h);
                    else d[i+1][j+a[i+1].w][k] = min(d[i+1][j+a[i+1].w][k], ans);

                    if(k == 0) d[i+1][j][k+a[i+1].w] = min(d[i+1][j][k+a[i+1].w], ans + a[i+1].h);
                    else d[i+1][j][k+a[i+1].w] = min(d[i+1][j][k+a[i+1].w], ans);

                    if(j + k == sum[i]) d[i+1][j][k] = min(d[i+1][j][k], ans + a[i+1].h);
                    else d[i+1][j][k] = min(d[i+1][j][k], ans);

                }
            }
        }
        int ans = INF;
        for(int i = 1; i <= maxw/2; i++) {
            for(int j = 1; j <= maxw/2; j++) {
                int h = d[n][i][j];
                int w = max(i, max(j, maxw - i - j));
                if(maxw - i - j == 0) continue;
                if(d[n][i][j] >= INF) continue;
                ans = min(ans, h*w);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

时间: 2024-12-17 20:53:55

LA 3637 - The Bookcase(DP)的相关文章

Tyvj P1034 尼克的任务 (DP)

背景 Background 题库靠大家,人人都爱它. 描述 Description 尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成. 尼克的一个工作日为N分钟,从第一分钟开始到第N分钟结束.当尼克到达单位后他就开始干活.如果在同一时刻有多个任务需要完成,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去写成,假如某些任务开始时刻尼克正在工作,则这些任务

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

Ural 1353 Milliard Vasya&#39;s Function(DP)

题目地址:Ural 1353 定义dp[i][j],表示当前位数为i位时,各位数和为j的个数. 对于第i位数来说,总可以看成在前i-1位后面加上一个0~9,所以状态转移方程就很容易出来了: dp[i][j]=dp[i][j]+dp[i][j-1]+dp[i][j-2]+.......+dp[i][j-9]: 最后统计即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <

HDU 4908 (杭电 BC #3 1002题)BestCoder Sequence(DP)

题目地址:HDU 4908 这个题是从m开始,分别往前DP和往后DP,如果比m大,就比前面+1,反之-1.这样的话,为0的点就可以与m这个数匹配成一个子串,然后左边和右边的相反数的也可以互相匹配成一个子串,然后互相的乘积最后再加上就行了.因为加入最终两边的互相匹配了,那就说明左右两边一定是偶数个,加上m就一定是奇数个,这奇数个的问题就不用担心了. 代码如下: #include <iostream> #include <stdio.h> #include <string.h&g

Sicily 1146:Lenny&#39;s Lucky Lotto(dp)

题意:给出N,M,问有多少个长度为N的整数序列,满足所有数都在[1,M]内,并且每一个数至少是前一个数的两倍.例如给出N=4, M=10, 则有4个长度为4的整数序列满足条件: [1, 2, 4, 8], [1, 2, 4, 9], [1, 2, 4, 10], [1, 2, 5, 10] 分析:可用动态规划解题,假设dp[i][j],代表满足以整数i为尾数,长度为j的序列的个数(其中每一个数至少是前一个数的两倍).那么对于整数i,dp[i][j] 等于所有dp[k][j-1]的和,其中k满足:

UVA542 - France &#39;98(dp)

UVA542 - France '98(dp) 题目链接 题目大意:之前题目意思还以为看懂了,其实没看明白,它已经把各个选手分在各自所在的区域里面,这就意味着第一次的PK的分组已经确定,而且冠军必须是从两个左右分区出来的胜利者才有机会pk冠军. 解题思路:那么从1-16这个大的区间内诞生出来的冠军可能是来自左边,也可能是右边,然后再左边右边的子区间递归找出冠军.f[i][l][r]表示l-r这个区间的胜利者是i的概率,那么假设i在区间的最左边,f[i][l][r] = Sum(f[i][l][m

HDU 4968 Improving the GPA(dp)

HDU 4968 Improving the GPA 题目链接 dp,最大最小分别dp一次,dp[i][j]表示第i个人,还有j分的情况,分数可以减掉60最为状态 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int t, avg, n; double dp1[15][405], dp2[15][405]; double get(int x) { if

URAL 1167. Bicolored Horses (DP)

题目链接 题意 :农夫每天都会放马出去,然后晚上把马赶入马厩,于是让马排成一行入马厩,但是不想马走更多的路,所以让前p1匹入第一个马厩,p2匹马入第二个马厩…………但是他不想让他的任何一个马厩空着,所有的马都必须入马厩.有两种颜色的马,如果 i 匹黑马与 j 匹白马同在一个马厩,不愉快系数是 i * j,总系数就是k个系数相加.让总系数最小. 思路 : dp[i][j] 代表的是前 i 个马厩放 j 匹马的最小不愉快系数值. 1 //1167 2 #include <cstdio> 3 #in

2014多校第七场1005 || HDU 4939 Stupid Tower Defense (DP)

题目链接 题意 :长度n单位,从头走到尾,经过每个单位长度需要花费t秒,有三种塔: 红塔 :经过该塔所在单位时,每秒会受到x点伤害. 绿塔 : 经过该塔所在单位之后的每个单位长度时每秒都会经受y点伤害. 蓝塔 : 经过该塔所在单位之后,再走每个单位长度的时候时间会变成t+z. 思路 : 官方题解 : 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define LL long long