首页 > 其他分享 >CF799D题解

CF799D题解

时间:2024-02-27 22:46:08浏览次数:25  
标签:min 题解 h0 w0 CF799D ans 矩形 dp

CF799D

这里更容易进入且有翻译

题意

给定一个长宽为 \(a\) 和 \(b\) 的目标矩形、一个宽高为 \(h\) 和 \(w\) 的初始矩形及 \(n\) 个操作 \(a_i\)。对于每个操作,可以将初始矩形的宽或高乘以 \(a_i\),求使目标矩形能放入初始矩形的最少操作(目标矩形可以旋转 90 度)。

解析

这题算是一道有趣的背包题。

由于 \(a, b \le 10^5\),不可能直接进行二维 dp。考虑到 \(a_i \ge 2\),又有 \(\left \lceil \log{10^5} \right \rceil = 17\),可以得出结论————至多只需要进行 34 个操作。

我们可以将操作数从大到小进行排序,设 \(i\) 为当前进行第几个操作,\(j\) 为初始矩形宽度,\(dp_{i, j}\) 为进行到第 \(i\) 个操作时初始矩形宽为 \(j\) 时高最大为多少。则可以得到转移方程:

\[dp_{i,j \times a_i} = \max(dp_{i - 1, j \times a_i} \times a_i, dp_{i - 1, j}) \]

初始化 \(dp_{0, w} = h\)。当 \(j \times a_i > \max(a, b)\) 时,可以将 \(j \times a_i\) 并入 \(\max(a, b)\),此做法不会对决策造成影响。

在每次计算转移之后对 \(dp_{i, j \times a_i}\) 进行判定是否符合题目要求,若符合,输出当前的 \(i\) 即为答案。要注意目标矩形可以做 90 度旋转(测试点 27 会卡)。

另外,观察每次转移时都只和 \(i - 1\) 有关,且 \(j < a_i\),可以用类似 01 背包的方式对数组进行滚动优化。

代码

#include <bits/stdc++.h>
#define LL long long
#define pii pair<int, int>
#define pll pair<LL, LL>

using namespace std;

vector<LL> dp(100005, 0);
LL a[100005];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    LL h0, w0, h, w, n;
    cin >> h0 >> w0 >> h >> w >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    //判定是否已符合条件
    if (h >= h0 && w >= w0 || h >= w0 && w >= h0)
    {
        cout << "0\n";
        return 0;
    }

    sort(a + 1, a + n + 1, greater<LL>());
    if (h >= h0 || h >= w0 || w >= h0 || w >= w0) //判断有一条边已符合条件的情况
    {
        a[0] = 1;
        for (int i = 1; i <= n; i++)
            a[i] *= a[i - 1];

        int ans = n + 5;
        if (h >= h0)
        {
            for (int i = 1; i <= n; i++)
                if (w * a[i] >= w0)
                {
                    ans = min(ans, i);
                    break;
                }
        }
        if (h >= w0)
        {
            for (int i = 1; i <= n; i++)
                if (w * a[i] >= h0)
                {
                    ans = min(ans, i);
                    break;
                }
        }
        if (w >= h0)
        {
            for (int i = 1; i <= n; i++)
                if (h * a[i] >= w0)
                {
                    ans = min(ans, i);
                    break;
                }
        }
        if (w >= w0)
        {
            for (int i = 1; i <= n; i++)
                if (h * a[i] >= h0)
                {
                    ans = min(ans, i);
                    break;
                }
        }

        cout << (ans > n ? -1 : ans) << "\n";
        return 0;
    }

    dp[w] = h; //dp数组初始化
    for (int i = 1; i <= n; i++)
        for (int j = max(w0, h0); j >= w; j--)
        {
            dp[min(j * a[i], max(w0, h0))] = max(dp[j], dp[min(j * a[i], max(w0, h0))]);
            dp[j] *= a[i];
            if (j * a[i] >= w0 && dp[min(j * a[i], max(w0, h0))] >= h0 || j >= w0 && dp[j] >= h0) //判断正放目标矩形的情况
            {
                cout << i << "\n";
                return 0;
            }
            if (j * a[i] >= h0 && dp[min(j * a[i], max(w0, h0))] >= w0 || j >= h0 && dp[j] >= w0) //判断旋转目标矩形的情况
            {
                cout << i << "\n";
                return 0;
            }
        }

    cout << "-1\n";
}

最后祝各位顺利AC。>w<

标签:min,题解,h0,w0,CF799D,ans,矩形,dp
From: https://www.cnblogs.com/ItsAiHAn/p/18038583

相关文章

  • [ABC303Ex] Constrained Tree Degree 题解
    AtCoder题面洛谷题面如果每个点的度数都知道了,那问题就转化成了P2290[HNOI2004]树的计数,直接求Prufer序列的个数即可,因为一个度数为\(d_i\)的点在Prufer序列中的出现次数是\(d_i-1\),所以答案是:\(\frac{(n-2)!}{\prod_{i=1}^{n}(d_i-1)!}\)。可以把\((n-2)!\)放到......
  • [COI2009] PLAHTE 题解
    首先对于每一个矩形,若\(x_2<0\),就将\(x_1,x_2\)均乘上\(-1\)再交换,对于\(y_1,y_2\)也做同样的操作。我们建立一个操作序列a[0~1000],和一个数组\(d\),每一个操作用\((x,y)\)表示,就是在\(d\)内把所有\(0\)到\(x\)的位置加上\(y\)。我们再定义一种新的操作\([x,y......
  • [USACO11NOV]Binary Sudoku G 题解
    定义一个\(3\times3\)的表格\(a\),表示每个小九宫格内1的个数的奇偶状态。再定义两个长为\(9\)的数组\(c0,c1\),表示每行每列上1的个数的奇偶状态。当\(d_{i,j}\)取反时,会将\(a_{[\frac{i}{3}],[\frac{j}{3}]},c0_i,c1_j\)各取反一次。要将\(a_{i,j}\)全部变为0......
  • [ABC286Ex] Don't Swim 题解
    我们首先求出线段与多边形的交点,如果交点个数\(<2\)或者有无数个交点,则可以直接输出\(S\)到\(T\)之间的距离。接下来我们考虑交点个数为\(2\)的情况。为了方便,我们记距离\(S\)最近的那个交点为\(P_1\),远的为\(P_2\)。举个例子:在这个例子中,直线\(ST\)将整个多边......
  • P3577 [POI2014]TUR-Tourism 题解
    考虑在无向图上进行dfs,可以得到很多棵dfs树(因为图不一定连通),这些树形成了一个森林。然后由任意两点间不存在节点数超过\(10\)的简单路径这个限制可以得出这些树的深度都不超过\(10\),然后可以想到树上状压dp。有一个重要的性质,就是无向图dfs树上的非树边,一定是回边,所以......
  • CF516E Drazil and His Happy Friends 题解
    题目传送门记\(d=\gcd(n,m)\),发现只有编号在模\(d\)意义下相同的人之间会产生影响,那么有解当且仅当每个剩余系内有至少一个人是快乐的。所以在\(d>b+g\)时直接输出-1即可。对于剩下的情况,先令\(n\leftarrow\fracnd,m\leftarrow\fracmd\),如果\(n<m\)那么把男女交......
  • [ARC140F] ABS Permutation (Count ver.) 题解
    洛谷题面传送门AT题面传送门发现不太好直接求,考虑将\(P\)映射到\(P^{-1}\)上,这样题目中的条件就变成了\(|P_i-P_{i+M}|=1\)。因此我们可以对模\(M\)的每个剩余系做\(M=1\)的情况,然后最后快速幂合并。考虑\(M=1\)的情况怎么做。记\(f_i\)表示\(K=i\)的方案数,......
  • [ARC112F] Die Siedler 题解
    题目传送门人类智慧题。发现\(2\)操作肯定是不劣的,所以能换则换。考虑将手上的牌转换成一个多进制的数,这样\(2\)操作就是其进位方法,\(1\)操作就是将当前的数加上牌包对应的数,答案就是其各位数字之和,不难发现其值为:\[\sum_{i=1}^nc_i\times2^{i-1}\times(i-1)!\]再考......
  • 2024.2.27模拟赛T2题解
    题目有一个神奇的结论\(\foralla<b<c,a\oplusc>min(a\oplusb,b\oplusc)\)然后就可以写出\(n^2\)dp,再用TRIE树优化即可code#include<bits/stdc++.h>usingnamespacestd;#defineN200005#defineintlonglongintn,k1,k2;inta[N],fl[2];constintm......
  • CF1392I Kevin and Grid 题解
    题目传送门\(\large\textbf{Statement.}\)给定两个序列\(a,b\),有一个\(n\timesm\)的网格图,每个点\((i,j)\)上有个权值\(a_i+b_j\),每个点和其上、下、左、右方相邻的点有连边。多次询问,每次给一个阈值\(x\),将图分为权值\(<x\)(蓝色)和\(\gex\)(红色)的两种连通块。一......