2017中国大学生程序设计竞赛 - 网络选拔赛 [1005 - CaoHaha's staff] 贪心

题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1005&cid=779

题目大意:在一个二维坐标网格里画线,可以画一条长度为1的边或者长度为根号2的对角线。给一个面积S,问至少需要多少画才能得到一个面积大于S的区域。

关键思想:贪心嘛,在周长一定的情况下 ,为了得到最大面积,一定要越接近正方形越好,并且一定是凸多边形。不然的话,找到凹边两边连起来得到一条对称轴,凹边对称之后得到的凸多边形周长相同,面积更大。

然后我们就开始考虑边长为2根号2的正方形,我们对这个正方形加边进行扩展,加一条边产生一个小梯形;再加一条边变成一个长方形,边长之差为根号2;再在较短边那里加一条边变成长的小梯形;再加一条边变成新的正方形,边长比最初的大了根号2,这就构成一个循环。需要注意的是,如果边长为根号2,则无法加边构成小梯形,需要特判。

代码预处理了数组,再用二分查找,0msAC。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define MAX 100010
int a[MAX];
int main()
{
    for(int i=0;i<4;i++)
        a[i] = 0;
    a[4] = 2;
    a[5] = 2;
    a[6] = 4;
    a[7] = 5;
    for(int i=8;i<MAX;i++)
    {
        if(i%4==1)
            a[i] = (i/4) -1 + a[i-1];
        else if(i%4==2)
            a[i] = 2*(i/4) + a[i-2];
        else if(i%4==3)
            a[i] = 3*(i/4) + a[i-3];
        else if(i%4 == 0)
            a[i] = (i/4)*(i/4)*2;
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        if(n==0)
        {
            cout<<"0"<<endl;
            continue;
        }
        int left = 0,right = MAX-1;
        int mid = (left+right)/2;
        while(left<right)
        {
            if(a[mid] < n)
                left = mid+1;
            else
                right = mid;
            mid = (left+right)/2;
        }
        cout<<left<<endl;
    }
    return 0;
}

 

posted @ 2017-08-19 22:40  哇咔咔咔  阅读(375)  评论(0编辑  收藏  举报