Codeforces Round #413 D. Field expansion (搜索)

传送门


题意

将原  h×w  的矩形扩展,使得其能够放置  a×b  的矩形。每次扩展可以从给定的 n ( n100000 ) 个数中选择一个数  Ai ,将  hhAi  或者  wwAi  ,其中每个数最多只能使用一次,问最少扩展多少次能满足条件,或不可能。

解题思路

首先可以想到,对于同样地对原矩形扩展 X 次,使用 n 个数中最大的 X 个数对矩形进行扩展必然是最优的。因此,对 n 个数从小到大进行排序,并优先选用可用的最大数。

给定的 n 个数对原  h×w  矩形进行扩展,则每次可以将 h 或 w 扩展  Ai  倍。因此,朴素地使用搜索的复杂度将可能达到  O(2100000)  。但是,对于  2Ai  ,且  1a,b,h,w100000  ,故  log210000017  ,即复杂度实际应该在  O(234)  。当然,这仍然无法满足。

考虑对问题进行优化,当经过处理的原矩形  H×W  使得可用的  Ai  都为 2 时,此时无需考虑将 2 如何分配的问题,当 H 或 W 尚有不足时,直接  ×2  即可;同时  log3100000=11  , O(222)  可在 1000 ms 内解决。故特判 2 可将问题复杂度缩小到可解范围。

#include<bits/stdc++.h>
using namespace std;
int a, b, h, w, n, A[100010];
int dfs(long long h, long long w, int idx)
{
    if(h>=a&&w>=b)    return n-idx;
    if(idx==0)  return -1;
    if(A[idx] == 2)//2的话 复杂度为2^34 所以特判
    {
        if(h<a) return dfs(h*2, w, idx-1);
        return dfs(h, w*2, idx-1);
    }
    else
    {
        int ansh = -1, answ = -1;
        if(h<a)
            ansh = dfs(h*A[idx], w, idx-1);
        if(w<b)
            answ = dfs(h, w*A[idx], idx-1);
        if(ansh==-1 || answ==-1)    return max(ansh, answ);//-1的话就把数组里的值用完了
        return min(ansh, answ);
    }
}
int main()
{
    scanf("%d %d %d %d %d",&a,&b,&h,&w,&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]);
    sort(A+1, A+n+1);
    int ansl, ansr;
    ansl = dfs(h, w, n);
    swap(a, b);
    ansr = dfs(h, w, n);
    if(ansl==-1 || ansr==-1)    printf("%d\n", max(ansl, ansr));
    else    printf("%d\n", min(ansl, ansr));//如果都没取完数组里的数 取一个最小的就好了
}


以上是别的大佬的看法。

我自己的想法是排序之后 取h w的小的那个。 然后a b 取小的那个

    if(h>w)
        swap(h,w);
    if(a>b)
        swap(a,b);

for(int i=1;i<=n;i++)
    {
        if(A[i]<=1)
            continue;
        h*=A[i];
        int cnt=A[i];
        A[i]=1;
        ans++;
        if(h>=a)//如果这里已经满足条件 那么不乘这个A[i] 看能不能把这个较大的倍数留给另一边。
        {
            if(w>=b)
            {
                cout<<ans<<endl;
                return 0;
            }
            int l=n,r=i;
            h/=cnt;
            while(l<=r)//二分找一下合适的A[l] 如果 A[l]满足条件 把A[i]还原。 用这个A[l]
            {
                int mid=(l+r)>>1;
                if(h*A[mid]>=a) r=mid-1;
                else l=mid+1;
            }
           // cout<<"**********"<<A[l]<<"            "<<A[i]<<endl;
            if(A[l]*h>=a)
            {
                A[l]=1;
                A[i]=cnt;
            }
            break;
        }
    }

剩下的就是另一边for一遍取从大倍数取到小的倍数就好了。 如果满足条件就输出ans 

这里只给出思路。 具体不知道能不能实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值