题是51nod上的 3330 Minecraft :题目地址(网站崩了就去按题号找一下)
输入一个n,n<=1e9,n是小方块个数,可以相当于已知矩形体积,求解最小表面积的长宽高为整数的解。
首先因为n的范围很大,不能用三重循环的做法,就是分别遍历长宽高,然后满足条件算出表面积维护最小值。
最简单的优化是把三重循环变成二重循环,参考poj 2363 ,相当于用体积公式去掉一重循环,已知长宽可以由V=abc得a=V/(b*c),然后同上,满足条件算出表面积维护最小值。
接下来就是能ac的思路了,第一步先求出n的所有质因数,就是不断除以2,除到不能除为止看能不能除以3、5、7…
第二步是把这些质因数存到动态数组里,分为五种情况,一是动态数组里没有值,这种情况只能是n=1,由表面积计算公式得s=6,输出即可;二是动态数组有唯一值,三是动态数组有唯二值,四是动态数组有唯三值,把值赋给矩形的边,剩下的补1,由表面积公式求出即可;五是动态数组中的值大于三个,由规律可知最大的质因数一定是矩形的其中一个边,然后不断改变矩形的其它两边(由不等式定理知三边最接近时表面积最小)(可理解为三边相减的绝对值最小的时候表面积最小)然后通过更新两条边的值算出绝对值相减最小的时候并记录三条边的值。ans为求出的最小表面积的结果。
#include<iostream>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
typedef long long ll;
vector<ll> ve;
ll ans=0x3f3f3f3f;
int judge(ll a,ll b,ll c){
if(b<c){
ll temp=b;
b=c;
c=temp;
}
return (a-c)+(a-b)+(b-c);
}
void solve(){
ll a,b,c=1;
ll min=0x3f3f3f3f;//三边维护值最小(绝对值)
a=ve[ve.size()-1];//一定是个大质因数,它不变,但是三边维护要用它
b=ve[ve.size()-2];
for(int i=0;i<ve.size()-2;i++){
c*=ve[i];
}
ll bb=b,cc=c;
int t=0;
while(true){
if(min>judge(a,b,c)){
min=judge(a,b,c);
bb=b;
cc=c;
}
b*=ve[t];
c/=ve[t];
if(t==ve.size()-3) break;
else t++;
}
ans=2*(a*bb+a*cc+bb*cc);
}
int main(){
ll n;
cin>>n;
while(n%2==0){
ve.push_back(2);
n/=2;
}
for(int i=3;i<=sqrt(n*1.0);i+=2){
while(n%i==0){
ve.push_back(i);
n/=i;
}
}
if(n>2){
ve.push_back(n);
}
int len=ve.size();
if(len==0) ans=6;
else if(len==1) ans=ve[0]*4+2;
else if(len==2) ans=2*(ve[0]*ve[1]+ve[0]+ve[1]);
else if(len==3) ans=2*(ve[0]*ve[1]+ve[0]*ve[2]+ve[1]*ve[2]);
else{
//找到三个边,三边维护绝对值差最小
solve();
}
cout<<ans<<endl;
return 0;
}