csu2146 神奇的金字塔(寻找通项)

D - 神奇的金字塔

 CSU - 2146 

总所周知,CSU没有金字塔,但在世界某地有一座神奇的金字塔。

神奇的金字塔位于N*N的网格地上。

第0分钟时,金字塔底面很小,只占据(x,y) 这个格子,之后每过一分钟,金字塔会长大,就算超过边界也会继续长大,不过边界外是无限深渊,所以超过边界的部分不算占据的面积,而且由于是无限深渊,不需要考虑什么时候被填满的问题。

那么现在问题来了,至少在第几分钟网格上才至少有C个格子被金字塔占据。

Input

每组数据每一行有4个整数,N,X,Y,C

哇,这题我居然卡了半天,菜哭。就是简单的找出通项然后找到符合条件的最短时间即可。至于如何找通项。我们一开始考虑无边界的情况,每秒的增长就是4t,利用求和公式就可得到1+2*t(t+1).这时由于存在边界,所以还需要把超出边界的增长减去,再加上减重复的。具体见图

黑色为第一秒的水,红色为第三秒。如无边界则此时水的格数就是13.

此时需要减去的是下图所示中的两个三角形

每个三角型的大小均是他们的高的平方,这里也就是4+4

但是可以看到这里实际上是减多了的

因此还需要加上重叠那一块的面积。这里就是1.

所以此时的水覆盖格数就是13-4-4+1=6

考虑到大三角重叠产生的小三角形比较难计算,这里来具体说明一下。

这就是一个起始点位于(x,y)的水源在边长为n的界中第t秒的扩张情况

这时各边的长度是

那么需要减去的两个大三角型的面积,这里就是(2-x+t)^2+(y+t-n+1)^2

再补上重叠的面积即是(y-x+t+1-n)*(y-x+t+2-n)/2

好了具体实现还是看代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
int n,x,y;
long long le(int t)
{
	long long ans=0;
	LL a=0,b=0,c=0,d=0;
	if(x-t<=1)//上 
	{
		a=(2-(x-t));
		ans+=a*a;
	}
	if(x+t>=n)//下 
	{
		b=(x+t+1-n);ans+=b*b;
	}
	if(y-t<=1)//左 
	{
		c=(1-(y-t))+1;ans+=c*c;
	}
	if(y+t>=n)//右 
	{
		d=(y+t-n)+1;ans+=d*d;
	}
	LL e=0,f=0,g=0,h=0;
	if(a>y&&c>x) e=min(a-y,c-x);
	if(a>(n-y)+1&&d>x) f=min(a-(n+1-y),d-x);
	if(b>y&&c>(n-x)+1) g=min(b-y,c-(n+1-x));
	if(b>(n-y)+1&&d>(n-x)+1)h=min(b-(n+1-y),d-(n+1-x));
	//cout<<a<<' '<<b<<' '<<c<<' '<<d<<' '<<e<<' '<<f<<' '<<g<<' '<<h<<endl;
	return ans-e*(e+1)/2-f*(f+1)/2-g*(g+1)/2-h*(h+1)/2;
} 
long long dp[2];
int main()
{
	long long c;
	while(cin>>n>>x>>y>>c)
	{
		long long t=1;
		dp[1]=1;
		if(c==1)
		{
			cout<<'0'<<endl;
			continue;
		}
		while(dp[1]<c)
		{
			dp[1]=1+(1+t)*2*t-le(t-1);
			//cout<<le(t-1)<<endl;
			//cout<<dp[1]<<endl;
			t++;
		}
		cout<<t-1<<endl;
	}
	
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值