【NOIP2018 模拟赛day1】塔

【题目描述】

小 A 想搭一个体积不超过 m 的塔, 他有各种大小的立方积木, 比
如边长为 a 的积木, 体积为 a^3, 现在小 A 需要你给一个 X, 每次小
A 会用一个体积不超过 X 的最大积木, 依次到搭好为止, 现在他想最
大化积木的个数, 同时在积木个数最大的情况下使 X 最大。

  • 【输入描述】
    一行一个数 m
  • 【输出描述】
    一行两个数, 最多积木数以及 X。
  • 【样例】
    48
    9 42
  • 【样例解释】
    X=23 或 42 都是 9 次, 42 = 3^3 + 2^3 + 7*1^3
    【数据范围】
    30%:m<=10^5
    50%:m<=10^10
    100%: m<=10^15

题解:

—这道题只有那么神奇了,宝宝看了n久n久都没懂,最后细细分析了一下样例,哦…..
—然后两种方法冒出来了:1.枚举(30分) 2.dp(100分)
dp:
–假设我们现在可以用的体积是left,那么我们有两种选择方式
1.放一块体积最大(a),但不超过left的积木
—这时剩下的体积是:left-a^3
2.直接把剩下的体积强行变成a^3
—这时剩下的体积是:a^3−1−(a−1)^3
具体证明如下:
因为a^3-1-(a-1)^3恒大于(a-1)^3-1-(a-2)^3,我们又要保证积木最多,及要使left尽量大,所以用选前者,但是,我们并不能知道m-a^3与其的大小关系,所以也要计算

pow(x,1.0/y)可以求x的根号下y次方


代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=1;

long long m;
long long x,ans;

long long cf(long long a){
    return a*a*a;
}

void dp(long long left,long long now,long long sum){
    if(!left){
        if(now>ans||(now==ans&&sum>x)){
            ans=now;
            x=sum;
        }
        return ;
    }
    long long a=(long long)pow(left,1.0/3);
    dp(left-cf(a),now+1,sum+cf(a));
    dp(cf(a)-1-cf(a-1),now+1,sum+cf(a-1));
}

int main(){
//  freopen("tower.in","r",stdin);
//  freopen("tower.out","w",stdout);
    cin>>m;
    dp(m,0,0);
    cout<<ans<<" "<<x;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值