1. 程式人生 > >【推導】【找規律】【二分】hdu6154 CaoHaha's staff

【推導】【找規律】【二分】hdu6154 CaoHaha's staff

print turn else 多邊形 pac 線段 取整 log 推導

題意:網格圖。給你一個格點多邊形的面積,問你最少用多少條邊(可以是單位線段或單位對角線),圍出這麽大的圖形。

如果我們得到了用n條邊圍出的圖形的最大面積f(n),那麽二分一下就是答案。

n為偶數時,顯然要盡量用斜邊去拼矩形,於是f(i)=i*i/4-1 (i mod 4 == 2),f(i)=i*i/4-1(i mod 4 == 0)。

當n為奇數時,盡量用i-1情況下的最長邊向外擴張一個單位,於是f(i)=f(i-1)+[(i+1)/4]*2-1(i mod 2 == 1),方括號表示下取整。

n過小時要特判一下。

#include<cstdio>
using namespace std;
typedef long long ll;
ll calc(ll i){
	if(i==1ll){
		return 0;
	}
	if(i==3ll){
		return 1ll;
	}
	if(i==5ll){
		return 5ll;
	}
	if(i%4ll==1ll){
		ll X=(i-1ll)*(i-1ll)/4ll;
		return X+(i+1ll)/4ll*2ll-1ll;
	}
	else if(i%4ll==2ll){
		return i*i/4ll-1ll;
	}
	else if(i%4ll==3ll){
		ll X=(i-1ll)*(i-1ll)/4ll-1ll;
		return X+(i+1ll)/4ll*2ll-1ll;
	}
	else if(i%4ll==0ll){
		return i*i/4ll;
	}
}
int T;
int main(){
	//freopen("g.in","r",stdin);
	scanf("%d",&T);
	ll x;
	for(;T;--T){
		scanf("%lld",&x);
		x*=2ll;
		ll l=1,r=2000000000ll;
		while(l<r){
			ll mid=(l+r)/2ll;
			if(calc(mid)>=x){
				r=mid;
			}
			else{
				l=mid+1;
			}
		}
		printf("%lld\n",l);
	}
	return 0;
}

【推導】【找規律】【二分】hdu6154 CaoHaha's staff