分析
在考场上我通过画图发现了对于n个点肯定用一个六边形围起来最优(假装四边形是特殊的六边形),我们发现可以将这个六边形分成两个梯形(梯形的高可以为0),然后我们便枚举两个梯形共同的底边和它们分别的高。代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int inf = 2e9+7;
int main(){
int n,m,i,j,k;
for(n=1;n<=50;n++){
int ans=inf;
int h1,h2,w;
for(h1=0;h1<=n;h1++)
for(h2=0;h2<=n;h2++)
for(w=1;w<=n;w++)
if(h1*(2*w-h1+1)+h2*(2*w-h2+1)-2*w>=2*n)
ans=min(ans,2*w+h1+h2+2);
printf("%d
",ans);
}
return 0;
}
通过这个代码我们可以打出一张表,大致如下:
6
8 9 10 11 12 12
13 14 14 15 15 16 16 17 17 18 18 18
19 19 20 20 20 21 21 21 22 22 22 23 23 23 24 24 24 24
于是我们发现每一行的个数分别为1,6,2*6,3*6......,而所有的数都是连续的,对于第i行这一行第一个数有i-2个,最后一个数有i个,其余的数每个均有i-1个。这样我们便可以求出n在哪一行然后暴力搞了。由于总行数最多有√n个,而每一行的数也很少,所以在找到这个规律之后直接搞就行了。注意特判n=1的情况。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int inf = 2e9+7;
int Ans[110000];
int main(){
int n,m,i,j=1,k;
scanf("%d",&n);
if(n==1){
puts("6");
return 0;
}
for(i=1;i<=20000;i++)
if(3*i*(i-1)+1>=n){
k=i;
break;
}
int la=(k-1)*6+1;
if(k==2)la=8;
n-=(1+3*(k-1)*(k-2));
for(i=1;i<=max(k-2,1);i++)
Ans[i]=la;
la++;
int sum=0;
for(i=max(k-2,1)+1;i<=(k-1)*6-k;i++){
sum++;
if(sum==k)sum=1,la++;
Ans[i]=la;
}
la++;
for(i=(k-1)*6-k+1;i<=(k-1)*6;i++)Ans[i]=la;
printf("%d
",Ans[n]);
return 0;
}