ZYB建围墙 题解

ZYB建围墙

题意

给你一个数 \(n\),求把这 \(n\) 个格子围起来所需的格子数的最小值。

思路

首先,我们尝试把图画出来枚举前面来找出规律。下面这张图里是 1~10 的距离。

好的,我们可以发现。在这个图中 7 这个图内部是六边形。外面一圈绿色的也是六边形。这个时候我们发现数据中有一部分是这么写的:

\[N = 6 \times \frac{k \times (k + 1)}{2} +1 \]

于是,我们考虑从这里入手。首先我们再次进行枚举可知,当 \(n = 7\) 时需要 \(12\) 个。当 \(n = 19\) 时需要 \(18\) 个。好的规律已经出来了。当 \(k\) 为整数的时候,我们可以得到当前的答案为 \(6 \times (k + 1)\)

在这个基础上,我们考虑进行扩展。当现在是一个六边形的时候。设现在的边长为 \(edge\) 那么每扩展 6 层就有能多围出来的量就为:\(e - 1,e,e,e,e,e + 1\)。那么我们就直接枚举接近 \(n\) 的一个满足内外都为六边形的状态。暴力一层层加到 \(n\) 就可以了。这里需要枚举的量很小。所以时间复杂度大致就为:\(O(\sqrt{n})\)

AC code

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace WYL{
	const int INF=1e9;
	const int N=1e3+10;
	int n,opt=0;
	int now=1,y=1,sy,x=6;
	int f[N]={0,6,8,9,10,11,12,12,13,14,14,15,15,16,16,17,17,18,18,18,19};
	bool check(int k){
		for(int i=1;i*i<=INF;i++){
			if(n==6*(i*(i+1)/2)+1){
				opt=i;
				return true;
			}
		}
		return false;
	}
	signed main(){
		cin>>n;
		if(check(n)){
			cout<<6*(opt+1)<<endl;
			return 0;
		}else{
			while(now+x<=n){
				now+=x;
				y++;
				x+=6;
			}
			sy=n-now;
//			cout<<sy<<" "<<y<<endl;
			if(sy==0){
//				cout<<"***"<<endl;
				cout<<x<<endl;
			}else{
//				cout<<x<<endl;
				cout<<x+(sy/y)+1<<endl;
			}
		}
		return 0;
	}	
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//	freopen("wall.in","r",stdin);
//	freopen("wall.out","w",stdout);
	WYL::main();
	return 0;	
}
posted @ 2024-10-17 22:16  Chillturtle  阅读(52)  评论(0)    收藏  举报
//雪花飘落效果 html { cursor: url('https://files.cnblogs.com/files/yyyzyyyz/%E6%8C%87%E9%92%88.ico'), auto; }