ZROI2018提高day1t1

传送门

分析

在考场上我通过画图发现了对于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;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9551749.html