首页 > 其他分享 >[SHOI2007]书柜的尺寸 题解

[SHOI2007]书柜的尺寸 题解

时间:2024-05-26 16:24:37浏览次数:23  
标签:int 题解 书柜 t1 t2 SHOI2007 该层 书本 dp

题目链接

设 \(f_{i,t1,t2}\) 表示前 \(i\) 本书,第一层的宽度为 \(t1\),第二层的宽度为 \(t2\),所需要的最小高度。
第三层宽度 \(t3=\sum_{i=1}^{i}t_i-t1-t2\)。

但本题还有一个重要限制:每层的高度取决于该层最高的书,如果直接按照顺序加入书本,从 \(dp\) 的状态来看,无法确定新书本能否成为最高的书。

为了解决这个问题,先将书本按照高度从大到小排序,按照从大到小的顺序加入书本,那么每层第一本加入的书就是该层最高的书。而从 \(dp\) 的状态可以看出该层有没有书(从 \(t1/t2/t3\) 是否为 \(0\) 即可看出),从而确定书本是否是第一次加入。

直接 \(dp\) 空间上难以承受,滚动数组优化即可。

本题使用刷表法更好些,可以使得 “加入” 这一操作更加直观。

总结:对于以一串数字中的最大值作为贡献的,考虑先排序,再进行 \(dp\)。

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N=2110;
int n;
int f[N][N],d[N][N];
struct node {
    int h,t;
}a[N];

int cmp(node x,node y) {
    return x.h>y.h;
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i].h>>a[i].t;
    sort(a+1,a+1+n,cmp);
    memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    int sum=0;
    for(int i=1;i<=n;i++) {
        memcpy(d,f,sizeof(f));
        memset(f,0x3f,sizeof(f));
        for(int t1=0;t1<=sum;t1++) {
            for(int t2=0;t2<=sum;t2++) {
                if(!t1&&t2) break;
                int t3=sum-t1-t2;
                if(t3<0||(!t1&&!t2&&t3)) break;
                if(t1==0) f[t1+a[i].t][t2]=min(f[t1+a[i].t][t2],d[t1][t2]+a[i].h);
                if(t1&&t2==0) f[t1][t2+a[i].t]=min(f[t1][t2+a[i].t],d[t1][t2]+a[i].h);
                if(t1&&t2&&t3==0) f[t1][t2]=min(f[t1][t2],d[t1][t2]+a[i].h);
                if(t1) f[t1+a[i].t][t2]=min(f[t1+a[i].t][t2],d[t1][t2]);
                if(t2) f[t1][t2+a[i].t]=min(f[t1][t2+a[i].t],d[t1][t2]);
                if(t3) f[t1][t2]=min(f[t1][t2],d[t1][t2]);
            }
        }
        sum+=a[i].t;
    }
    LL minn=1e18;
    for(int t1=1;t1<=sum;t1++) {
        for(int t2=1;t2<=sum;t2++) {
            int t3=sum-t1-t2;
            if(t3<=1) continue;
            minn=min(minn,1ll*max({t1,t2,t3})*f[t1][t2]);
        }
    }
    cout<<minn;
    return 0;
}

标签:int,题解,书柜,t1,t2,SHOI2007,该层,书本,dp
From: https://www.cnblogs.com/zhangyuzhe/p/18213818

相关文章

  • CCF-GESP 等级考试 2024年3月认证C++一级真题解析
    2024年03月真题1单选题第1题C++表达式(3-2)*3+5的值是()。A.-13B.8C.2D.0正确答案:B.8解析:首先计算括号中的表达式(3-2),得到(1)。接下来进行乘法运算(1*3),得到(3)。最后进行加法运算(3+5),得到(8)。因此,表达式的值是(8)。第2题C++......
  • 题解:P6880 [JOI 2020 Final] オリンピックバス
    一个比较重要的性质:反转的边要在最短路上才会有贡献。我们可以先跑一遍最短路,记录下整颗最短路树,然后暴力的对每一条边进行判断,反转。我们建正反图各两个,分别以\(1\),\(n\)为起点。\(n\),\(1\)为终点。然后对每个图跑最短路,记录下最短路树。若不反转任何一条边,则答案为\(1\)......
  • 题解:CF1119D Frets On Fire
    大水题。首先,若区间内只有一根弦,不会对答案有贡献。我们思考如何对答案产生贡献。我们知道,对于每一个\(s_i\),都会产生一段\(s_i+r-l\)的连续序列,在对\(s\)数组排序后,若每个\(s_i+r-l\ges_{i+1}\)则答案为\(s_n+r-(s_1+l)+1\)。若够不到下一位呢?我们在\(s_n+r-(s_1+l......
  • UVA11922 Permutation Transformer 题解
    题目传送门前置知识无旋treap解法与luoguP3391【模板】文艺平衡树不同的是本题翻转后需要放到整个序列的末尾。由于需要翻转后放到末尾,故无旋Treap在维护文艺平衡树的过程中合并时跳着合并即可。代码#include<bits/stdc++.h>usingnamespacestd;#definelllong......
  • 题解【CF798D Mike and distribution】
    题目链接思考方向:构造方法满足\(A\)的要求,再满足\(B\)的要求。如果只考虑\(A\),有一种显然的方案:将\(A\)从大到小排序,选出前\(\left\lfloor\frac{n}{2}\right\rfloor+1\)大的即可。但这样显然难以扩展,所以需要另寻方案。由于题目提供了额外的\(+1\),所以先将最大的......
  • UVA1674 闪电的能量 Lightning Energy Report 题解
    题目传送门前置知识树链剖分|线段树解法树链剖分后维护一个支持区间修改,单点查询的线段树即可。也可以树上差分,同146.DFS序3,树上差分1的\(1,2\)操作,时间复杂度比树链剖分更优。代码#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#define......
  • CF1141E Superhero Battle 题解
    题目传送门简化题意给定\(H,n\)和一个长度为\(n\)的序列\(d\),求一个最小的\(m\)使得\(H+\sum\limits_{i=1}^{m}d_{(i-1)\bmodn+1}\le0\)。解法将式子移项后得到\(\sum\limits_{i=1}^{m}-d_{(i-1)\bmodn+1}\geH\)。将\(\sum\limits_{i=1}^{m}-d_{(i-1)\bmo......
  • SP14943 DRTREE - Dynamically-Rooted Tree 题解
    题目传送门前置知识树链剖分|线段树解法树剖换根,子树查询板子。类似换根DP的思路,我们发现换根后仅有祖先、子树、深度等会随祖先的变化而变化。设\(rt_{i}\)表示第\(i\)次操作的树根,\(x_{i}\)表示第\(i\)次操作的节点。接着进行大力分讨。当\(rt_{i}=x_{i}\)......
  • 图的dfs遍历题解
    本蒟蒻又来做题啦!看看今天做啥题。。。。题目描述时间:1s 空间:256M题目描述:给出一个无向图和一个起点s,输出这个图从s结点开始的DFS遍历序列。规定:节点邻居按照输入的顺序遍历输入格式:共M+1行。第11行包含33个正整数N,M,s,表示有N个点,M条边,起点为s。第2~M+1行包含2个用......
  • 【题解】 [USACO 2009 Mar] Cow Frisbee Team S
    题目描述题意分析从\(N\)个整数中取若干个(不能不选),且取的数之和为\(F\)的倍数的总方案数对\(10^8\)取余的值。思路这道题是一道二维线性DP。那么根据线性DP的解题方法。首先,找出题目的阶段性。这道题显而易见方案数随着选择的个数而变化,那么这道题就以选择的个数作为阶段......