[Codeforces 680D] Bear and Tower of Cubes //贪心+map暴力

Problem

题目链接

题意:给一个体积上限m (<=1015),要求找到一个X∈[1,m],使能选出来的正方体数量最多(),并且数量相同时,让X最大化()。输出最多数量和在该数量下的最大X。[选正方体的方法为,在剩余体积下,必须优先选用小于等于该体积的最大的正方体]


Solutions

贪心+map暴力 //我的做法

思路:
ans1: 贪心使最大数量尽可能大,就要让小的正方体尽可能多,设当前正方体体积和为now,从小到大枚举边长i,设use为当前边长正方体取的数量,一定有now+use* i * i * i <(i+1) * (i+1) * (i+1),所以use最大只能取到使不等式左边<右边并且左边<=m的最大值。一直这样贪心取直至!(now<=m),可得最大数量ans1。在过程中,用map记录下来每个正方体选取的数量。并且把所得的体积和now传给ans2。
ans2: 从大到小枚举map里的每个正方体,枚举它能增大到的边长,并每次扫描一遍map判断将它增大是否合法,合法就更新ans2。
最后的ans1和ans2就是答案。[暴力可行的原因是观察到当m取上限时ans1为18, 所以暴力复杂度很低]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef map<ll,int>::iterator IT;
ll m,ans1,ans2,ans2_,now;
map<ll,int>mp;
int cnt;
ll solve1(ll m,ll &now){
	ll k=0;
	for(ll i=1;i<=1e5&&i*i*i<=m;i++){
		ll t=min((i+1)*(i+1)*(i+1)-1,m)-now;
		ll use=t/(i*i*i);
		if(use>0)mp[i]=use;
		k+=use;
		now+=use*i*i*i;
	}
	return k;
}
void solve2(int n,ll &all){
	ll t=all,rest;
	IT it=mp.end();it--;
	while(1){
		ll c=it->second,v=it->first,k=0;
		if(v==0)break;
		if(!c){it--;continue;}
		t=all-v*v*v;
		rest=m-t;
		for(ll j=v+1;j<=1e5&&j*j*j<=m;j++)
			if(j*j*j<=rest)k=j;else break;
		if(!k){it--;continue;} 
		it->second--;
		ll flag,sum;
		for(ll j=k;j>=v+1;j--){
			mp[j]++;
			flag=1,sum=0;
			for(IT jt=mp.begin();jt!=mp.end();jt++){
				ll cj=jt->second,vj=jt->first;
				sum+=vj*vj*vj*cj;
				if(sum>=(vj+1)*(vj+1)*(vj+1)){flag=0;break;}
			}
			if(flag)break;else mp[j]--;
		}
		if(flag)all=sum;
		else it->second++;
		it--;
	}
}
int main(){
	cin>>m;mp[0]=0;
	ans1=solve1(m,ans2);
	solve2(ans1,ans2);
	cout<<ans1<<" "<<ans2;
}

dfs+贪心 //官方做法

思路:
对于一个给定的限制m,考虑最大那块正方体的选择,设最大的<=m的正方体是k3
1.取k3,那么下次限制为m-k3
2.取(k-1)3,那么下次限制为k3-1-(k-1)3
3.取(k-2)3,那么下次限制为(k-1)3-1-(k-2)3
显然取(k-2)不如取(k-1)优 [这里正方体数量和总体积大小都不如取(k-1)优],所以对于给定的限制m只需要考虑取k3或(k-1)3,然后对新的限制dfs进行。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll m,ans1,ans2;
void dfs(ll m,ll sum,ll cnt){
	if(m==0){
		if(cnt>ans1||cnt==ans1&&sum>ans2){ans1=cnt;ans2=sum;}
		return;
	}
	ll k=0;
	for(ll i=1;i<=1e5;i++)if(i*i*i<=m)k=i;else break;
	dfs(m-k*k*k,sum+k*k*k,cnt+1);
	if(k!=1)dfs(k*k*k-1-(k-1)*(k-1)*(k-1),sum+(k-1)*(k-1)*(k-1),cnt+1);
}
int main(){
	cin>>m;
	dfs(m,0,0);
	cout<<ans1<<" "<<ans2;
}

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/105086009