CF799D题解

CF799D

这里更容易进入且有翻译

题意

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

解析

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

由于 a,b105,不可能直接进行二维 dp。考虑到 ai2,又有 log105=17,可以得出结论————至多只需要进行 34 个操作。

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

dpi,j×ai=max(dpi1,j×ai×ai,dpi1,j)

初始化 dp0,w=h。当 j×ai>max(a,b) 时,可以将 j×ai 并入 max(a,b),此做法不会对决策造成影响。

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

另外,观察每次转移时都只和 i1 有关,且 j<ai,可以用类似 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<

posted @   OEAiHAN  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示