【CF679B】Bear and Tower of Cubes

题意

对于一个数 x x x,每次贪心地找到不小于剩下的数的最大的正整数的立方,减去这个数,并重复直至变成 0 0 0,操作次数即为 x x x的贡献。
[ 1 , m ] [1,m] [1,m]中找到最大的贡献及对应的数最大值。

思路

其他题解给出了二分/ d f s dfs dfs的做法,这里给出一种 D P DP DP的做法。

m m m分解为 ∑ a k 3 t k \sum{a_k^{3}t_k} ak3tk,其实总共分解出来的数不多,考虑可以通过以下方式计算答案:枚举 k k k,选取 a k 3 a_k^3 ak3的最后一个,不小于 a k 3 a_k^3 ak3的都保留,小于的都忽视, a k 3 a_k^3 ak3其拆开成最优的方案,与不小于 a k 3 a_k^3 ak3的贡献合起来。

接下来就考虑 x 3 x^3 x3的贡献:将 x 3 − 1 x^3-1 x31分解,按照上面的方法计算,最后考虑 x 3 x^3 x3本身。

时间复杂度为 O ( m 3 ) O(\sqrt[3]{m}) O(3m ),答案最大也只有 18 18 18,常数可以接受。

Code

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define hehe pair<long long,long long>
#define fir first
#define sec second
#define pb push_back
#define inf 1000000007
#define N 100005
using namespace std;
long long read()
{
	long long x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<1ll)+(x<<3ll)+ch-48,ch=getchar();
	return x*f;
}
void write(long long x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
long long n,cb[N],lim;
vector<hehe>v;
hehe ans,f[N];
long long cube(long long x)
{
	return x*x*x;
}
long long ncb(long long x)
{
	return (long long)pow((double)x,(double)1/(double)3);
}
void solve(long long x)
{
	v.clear();
	for(long long t,d;x;)
	{
		t=ncb(x);
		while(cb[t]>x)t--;
		while(t<lim&&cb[t+1]<=x)t++;
		d=x/cb[t];
		v.pb({t,d});
		x-=d*cb[t];
	}
}
hehe dp(long long x)
{
	long long sum=0,total=0;
	hehe ans={0,0};
	for(auto &aut:v)
	{
		long long t=aut.fir,d=aut.sec;
		long long temp=sum+(d-1)+f[t].fir,size=total+cb[t]*(d-1)+f[t].sec;
		if(temp>ans.fir||(temp==ans.fir&&size>ans.sec))ans.fir=temp,ans.sec=size;
		sum+=d;
		total+=d*cb[t];
	}
	return ans;
}
int main()
{
	n=read();
	lim=ncb(n)+2;
	for(long long i=1;i<=lim;i++)
	{
		cb[i]=cube(i);
	}
	for(long long i=1;i<=lim;i++)
	{
		long long temp=cb[i]-1;
		solve(temp);
		f[i]=dp(temp);
		if(!f[i].fir)f[i].fir=i,f[i].sec=cb[i];
	}
	solve(n);
	ans=dp(n);
	printf("%lld %lld\n",ans.fir,ans.sec);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值