题目
TonyFang打算送你一些立方体。
你需要在[1,n][1,n]中选择一个整数kk。在送你的立方体的体积和不超过kk的情况下,TonyFang会不断给你一个边长为正整数且尽可能大的立方体。
你需要求出最多能得到多少个立方体,以及在此条件下,kk的最小值和最大值。
Input
一行一个整数nn。
Output
三行,每行一个整数,分别表示最多立方体个数,容量最小值和容量最大值。
Examples
14
7
7
14
Notes
对于20%20%的数据,n≤1000n≤1000。
对于40%40%的数据,n≤100000n≤100000。
对于100%100%的数据,1≤n≤10151≤n≤1015。
对于每组数据,第一行正确可以得到30%30%的分数,第二行正确可以得到20%20%的分数,第三行正确可以得到50%50%的分数。请不要输出空行,不会的几行可以随便输出一个数。
思路
显然最后取走的立方体体积和恰好是 k,那么一种取立方体的方
案就对应了一个 k。
一个方案合法当且仅当取走的立方体从小到大排序后满足
x13+ x23+ + xi3 < (xi + 1)3。
对于前两问,从 x1 开始确定每个数。显然 xi 越小是越优的,直
接贪心即可。
对于第三问,考虑两个方案 x, y,如果 xi > yi 并且
xi+1 = yi+1, xi+2 = yi+2, …, xm = ym,那么 x 的体积和显然大于
y。因此,我们从 xm 开始确定每个数,在保证个数的前提下,最
大化当前 xi
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll r[100010],e[25],f[25],n;
int yjy[25],siz;
int main()
{
scanf("%lld",&n);
for(ll i=1; i<=100000; ++i)
{
r[i]=i*i*i;
}
ll ans;
ans=0;
int cnt=1;
while (1)
{
while(ans+r[cnt]>=r[cnt+1]&&ans+r[cnt]<=n)
cnt++;
ans+=r[cnt];
siz++;
yjy[siz]=cnt;
if(ans>n)
{
ans-=r[cnt];
siz--;
break;
}
}
for(int i=1; i<=siz; ++i)
e[i]=e[i-1]+r[yjy[i]];
printf("%d\n",siz);
printf("%lld\n",ans);
ll as=ans;
int o;
for(int i=siz; i>=1; --i)
{
while(as+r[yjy[i]+1]-r[yjy[i]]<=n)
{
o=0;
yjy[i]++;
for(int j=i; j<=siz; ++j)
{
f[j]=e[j];
e[j]+=r[yjy[i]]-r[yjy[i]-1];
if(e[j]>=r[yjy[j]+1])
o=1;
}
if(o)
{
for(int j=i; j<=siz; ++j)
e[j]=f[j];
yjy[i]--;
break;
}
as+=r[yjy[i]]-r[yjy[i]-1];
}
}
printf("%lld",as);
}