HDU-6154 CaoHaha's staff (找规律+二分)

来源:互联网 发布:诺亚方舟 知乎 编辑:程序博客网 时间:2024/06/08 05:18

这道题说了一长串背景,刚开始硬是没看懂。其实题意也是很简单的,就是在一个网格坐标系中,假设一小格的尺寸为1,然后给你个尺寸为N的图形,让你画个封闭的线条把这个图形包起来,在网格中,你只能画小方格的边或者对角线,并且每画一笔就要花费1分钟的时间。最后输出最小时间。

注意,所给的图形的形状可以自由变化。

我们先来找找规律。

首先尺寸为1,你可以这样围:,也可以这样:(这时我们选取第二种围法,即优先画出可围尺寸最大的线条,然后看看能不能把图形装进去)

尺寸为2(4min):尺寸为3(6min):尺寸为4(6min):

尺寸为5(7min):尺寸为6(8min):

其实这个线条的变化应该是这样的:

其中数字表示所需要的笔画次数。

所以不难发现笔画次数的变化从6开始每次都加1。那么线条所围图形的最大尺寸又是如何变化的呢?

从笔画为6开始,每次笔画加1,所围成的图形就会多一个梯形或者矩形,不难发现当笔画数为奇数时就是梯形,偶数就是矩形。

所以最大尺寸=上一个尺寸+梯形或矩形尺寸。而梯形和矩形的尺寸变化我们也可以发现,它是每出现两次后其底边长会加1。

若笔画数为t,那么(t>=6)为什么梯形和矩形的下标为t/4呢,首先是上个梯形与下个梯形之间间隔2个单位,其次每过2个梯形后其大小才会增长。


之后我采用打表的方法,所以这个式子没有继续往下推。

我的代码如下:

#include <cstdio>using namespace std;typedef unsigned long long ULL;const int MAX=1e5+1;int V[MAX];int V_MAX;void init_V(){    ULL v=4;    for(int i=7;i<MAX;i++)    {        if(i&1)            v+=(i-3)/4;        else            v+=i/4*2-(i-4)/4;        V[i]=v;        if(v>1e9)        {            V_MAX=i;            break;        }    }}int bf(int n){    int low=7,high=V_MAX,mid;    while(low<=high)    {        mid=(low+high)/2;        if(n<V[mid])            high=mid-1;        else            low=mid+1;    }    if(n<=V[mid-1])        return mid-1;    if(n<=V[mid])        return mid;    else        return mid+1;}int main(){    int t;    scanf("%d",&t);    init_V();    while(t--)    {        ULL n;        scanf("%I64u",&n);        if(n<=2)            printf("4\n");        else if(n<=4)            printf("6\n");        else            printf("%d\n",bf(n));    }    return 0;}