https://codeforces.com/problemset/problem/799/D
小L有一块大小为h × w的农田,但是这个农田太小了。幸运的是有 n 个延伸道具。第 i 个道具可以让农田的长或宽乘上 ai。每个延伸道具最多只能用一次。
现在他想在农田里面放一个大小为 a × b 的东西(可以横放也可以竖放),问最少用几个延伸道具。
思路:
贪心来看,取最大的。最小的2也就只有几十次。
但是如果是除法,会涉及到状态没有遍历到。因为被除数可能不止1e5.改成递推的乘。
最后跑两次dp每次check2回就好。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL dp[35][maxn];
LL pd[35][maxn];
LL p[maxn];
bool cmp(LL A,LL B){
return A>B;
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL a,b,h,w,n;cin>>a>>b>>h>>w>>n;
for(LL i=1;i<=n;i++){
cin>>p[i];
}
sort(p+1,p+1+n,cmp);
memset(dp,0,sizeof(dp));
dp[0][h]=w;//
for(LL i=1;i<=min((LL)34,n);i++){
for(LL j=1;j<=100000;j++){
dp[i][j]=max( min((LL)100000,dp[i-1][j]*p[i]),dp[i][j]);
dp[i][min((LL)100000,j*p[i])]=max(dp[i][min((LL)100000,j*p[i])],dp[i-1][j]);
}
}
LL ans=1e18;
for(LL i=0;i<=min((LL)34,n);i++){
for(LL j=a;j<=100000;j++){
if(dp[i][j]>=b){
ans=min(ans,i);
}
}
}
for(LL i=0;i<=min((LL)34,n);i++){
for(LL j=b;j<=100000;j++){
if(dp[i][j]>=a){
ans=min(ans,i);
}
}
}
memset(pd,0,sizeof(pd));
pd[0][w]=h;//
for(LL i=1;i<=min((LL)34,n);i++){
for(LL j=1;j<=100000;j++){
pd[i][j]=max(min((LL)100000,pd[i-1][j]*p[i]),pd[i][j]);
pd[i][min((LL)100000,j*p[i])]=max(pd[i][min((LL)100000,j*p[i])],pd[i-1][j]);
}
}
for(LL i=0;i<=min((LL)34,n);i++){
for(LL j=b;j<=100000;j++){
if(dp[i][j]>=a){
ans=min(ans,i);
}
}
}
for(LL i=0;i<=min((LL)34,n);i++){
for(LL j=a;j<=100000;j++){
if(dp[i][j]>=b){
ans=min(ans,i);
}
}
}
if(ans==1e18){
cout<<"-1"<<"\n";
}
else cout<<ans<<"\n";
return 0;
}