1.下棋的贝贝【算法赛】 - 蓝桥云课 (lanqiao.cn)
我们按照贪心的思想,逆时针进行放置棋子(当然顺时针也可以),获得的增益最大:
因为按照矩形放置棋子,上下左右的邻居都可以获得增益:
内圈
首先外圈不一定可以铺满,也不知道会铺到哪里去,但是内圈一定是铺满的,我们先算内圈的贡献和,再看还剩多少可以铺外圈。
首先我们用给定的n,对其就平方根得出内圈边长m:
假设n是18,那么肯定是有一个4*4的正方形,再进行延伸得到的:
4*4的正方形就是内圈,多余的2个铺到外圈:
当我们求出内圈边长m之后:
我们发现内圈的4个角的地方只能接触2个面:
因此这四个角的贡献我们可以用来表示:(m-2)*(m-2)是内圈1角的面积,*4是因为有4个角:
除了四个角剩下的地方每个可以接触三个面,一共有4个:
我们把圆球减去,发现每条边就变为m-1了:
因此我们可以用(m-1)*4 * 3-4来表示:即由4个m-1的组成,每个接触3条边,减去4个球。
然后内圈排完了,看有没有剩的,有剩的我们接着外圈继续排。还是拿18举例,18可以变为一个基础的4*4矩阵,但是肯定还有剩余的,因为4 * 4=16,外圈还要再排两个。
外圈排第一个的时候只能接触到1个面,如紫色球部分:
第二个第三个第四个……都可以贡献到2个面,如红色球部分:
直到第m个,我们发现又只能贡献1个面了:紫色球部分:
我们发现四个角(紫球)都只能接触一个面,而其他部分(红球)则可以接触两个面。
外圈
因此我们需要考虑四种1情况:
第一种情况,没有排到第二个角:
对于这种情况,我们只需要把特例减掉,即紫色球部分(只接触一个面,则只有两个贡献),红球部分接触两个面,有4个贡献。
我们用 2+(x-1)*4 表示,其中2是特例(紫球)贡献的(接触一个面2个贡献),
x-1就是把特列(紫球)减掉,再乘上4个贡献(红球部分,接触两个面)
第二种情况,排到第二个角:
这时就有两个特例了(两个紫球):
加上这两个特例的贡献:2*2=4
再减去这两个特例:x-2
乘剩下的贡献(红球):4
所以公式为:4+(x-2)*4
第三种情况,排到第三个角:
此时有3个特例,我们
加上3个特例的贡献:2*3=6
减去3个特例:x-3
乘剩下部分(红球,接触两个面)的贡献:*4
总结公式为:6+(x-3)*4
第四种情况,排到第四个角:
此时4个特例:
加上4个特例的贡献:2*4=8
减去4个特例: x-4
乘其他部分(红球)的贡献:*(2*2)
code
n最大1e18,一定要开long long
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n=0;cin>>n;
//特殊情况,只有1个没有邻居
if(n==1)
{
cout<<0;
return 0;
}
int m=sqrt(n); //求内圈边长
//内圈
int sum=(m-2)*(m-2)*4+(m-1)*4*3-4; //内圈的贡献
int x=n-m*m; //看还有多少剩余的要在外圈排
m++; //新的外围边长,内圈边长+1
//外圈
if(x) //如果有剩余的
{
if(x<=m-1) //如果没走到第二个角
{
sum+=2+(x-1)*4; //接触面为1的紫球的贡献 +( 减去一个紫球得到的接触面为2的红球的个数*其贡献值)
}
else if(x<=2*m-1) //如果走到了第二个角
{
sum+=4+(x-2)*4; //接触面为1的2个紫球的贡献 +( 减去2个紫球得到的接触面为2的红球的个数*其贡献值)
}
else if(x<=3*m-1) //如果走到了第三个角
{
sum+=6+(x-3)*4; //接触面为1的3个紫球的贡献 +( 减去2个紫球得到的接触面为2的红球的个数*其贡献值)
}
else if(x<=4*m-1) //如果走到第四个角
{
sum+8+(x-4)*4; //接触面为1的4个紫球的贡献 +( 减去4个紫球得到的接触面为2的红球的个数*其贡献值)
}
} cout<<sum;
return 0;
}