Description
总所周知,CSU没有金字塔,但在世界某地有一座神奇的金字塔。
神奇的金字塔位于N*N的网格地上。
第0分钟时,金字塔底面很小,只占据(x,y) 这个格子,之后每过一分钟,金字塔会长大,就算超过边界也会继续长大,不过边界外是无限深渊,所以超过边界的部分不算占据的面积,而且由于是无限深渊,不需要考虑什么时候被填满的问题。
那么现在问题来了,至少在第几分钟网格上才至少有C个格子被金字塔占据。
Input
每组数据每一行有4个整数,N,X,Y,C
其中,n,x,y,c<=109,c<=n2
Output
对于每组数据,输出一行
一行仅包含一个整数,表示至少过几分钟图上才至少会有C个格子被占据
Sample Input
9 3 8 10
Sample Output
2
Hint
思路:这题第一次使用bfs,果然TLE了。
然后观察发现,格子数量的增长是有规律的,给定时间,是可以算出当前时刻下格子的数量,然后要减去超出边界的格子,加上减去两次的格子数量(一直卡在这里,最后是参考AC代码)。而给定时间可以想到二分法寻找最短时间。
假定初始格子所在的位置为(X,Y),经过的时间为t,则格子的数量为1+t * t * 2 + 2 * t
格子距离上下左右的边界分别为:X-1,N-X,Y-1,N-Y
超出边界部分的面积也很容易求得(按1,3,5,7,...,2k+1的规律增长),是一个平方数
往上超出边界的格子数为:;往下超出边界的格子数量为:(左边和右边同理)
然后就是求多减去的面积(重叠部分):
假设红色的为X-1,绿色的为Y-1,则红色加绿色的为t,t必须要大于红色的线+绿色的线+1才会有重叠部分的方格(画方格会更好理解),其它三个方向同理。这个重叠部分的面积为一个等差数列(1,1+2,1+2+3,...)
#include<cstdio>
#include<string.h>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<algorithm>
using namespace std;
long long N, X, Y, C;
int main()
{
while (scanf("%lld %lld %lld %lld", &N, &X, &Y, &C) != EOF)
{
long long sum = 0L, ans = 0L;
long long l = 0L, r = N * 2 - 1;
long long ts = X - 1, tx = N - X;
long long tz = Y - 1, ty = N - Y;
while (l < r)
{
long long mid = (l + r) / 2;
sum = mid * mid * 2 + 2 * mid + 1;
//减去超出范围的面积
if (mid > ts)
sum -= (mid - ts) * (mid - ts);
if (mid > tx)
sum -= (mid - tx) * (mid - tx);
if (mid > tz)
sum -= (mid - tz) * (mid - tz);
if (mid > ty)
sum -= (mid - ty) * (mid - ty);
//加上可能多减的面积
if (mid > ts + tz + 1)
sum += (mid - ts - tz - 1) * (mid - ts - tz) / 2;
if (mid > tz + tx + 1)
sum += (mid - tz - tx - 1) * (mid - tz - tx) / 2;
if (mid > tx + ty + 1)
sum += (mid - tx - ty - 1) * (mid - tx - ty) / 2;
if (mid > ty + ts + 1)
sum += (mid - ty - ts - 1) * (mid - ty - ts) / 2;
if (sum >= C) //在mid时间内占据超过C个格子,时间可以继续缩短
{
ans = mid;
r = mid;
}
else
l = mid + 1;
}
printf("%lld\n", ans);
}
return 0;
}