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; }
边完善自己边认识自己