【题目描述】
小 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;
}