CodeForces 799D :Field expansion(压入一维作为存储的dp)

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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值