题意
将原 h×w 的矩形扩展,使得其能够放置 a×b 的矩形。每次扩展可以从给定的 n ( n≤100000 ) 个数中选择一个数 Ai ,将 h→h⋅Ai 或者 w→w⋅Ai ,其中每个数最多只能使用一次,问最少扩展多少次能满足条件,或不可能。
解题思路
首先可以想到,对于同样地对原矩形扩展 X 次,使用 n 个数中最大的 X 个数对矩形进行扩展必然是最优的。因此,对 n 个数从小到大进行排序,并优先选用可用的最大数。
给定的 n 个数对原 h×w 矩形进行扩展,则每次可以将 h 或 w 扩展 Ai 倍。因此,朴素地使用搜索的复杂度将可能达到 O(2100000) 。但是,对于 2≤Ai ,且 1≤a,b,h,w≤100000 ,故 log2100000≈17 ,即复杂度实际应该在 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
这里只给出思路。 具体不知道能不能实现