CCPC2017网络赛 1005
题意:询问T次,每次给出面积N,在网格坐标系中,每1秒可以画1条长根号2的对角线 或者 长为1的横 或者 竖。问最少画多少条线使得围成的面积>=N;
思路:先求画M条线(即M个点)能达到的最大面积是多少。。。
常识告诉我们越靠近斜45度正方形的面积就越大(每个点间的距离都是最长根号2了。。)
那么我们尽量摆成斜45度正方形,于是有下表
点数 最大面积
4 2 斜45度
5 ?
6 ?
7 ?
8 8 斜45度
9 ?
10 ?
11 ?
12 18 斜45度
....
那么9个点怎么画?多了一个点,想了很久,不断瞎画,发现点数一定时,尽量成为一团面积会更大
最优解是从8个点的图向外延伸,删一个点补两个点。
下图是8个点到12个点的最优解变化
这个图出来就好说了,把之前的表填满
通过面积的不断变换,找到下面的规律了。
点数 最大面积
4 2 斜45度
5 2.5=2+0.5
6 4 =2.5+0.5+1
7 5.5=4+0.5+1
8 8 =5.5+0.5+1+1 斜45度
9 9.5 =8+1.5
10 12 =9.5+1.5+1
11 14.5=12+1.5+1
12 18 =14.5+1.5+1+1 斜45度
用一个数组ptos[i] 预处理点数i围成的最大面积,
二分STL找到刚好大于面积N的最小点数,输出就好,一次就AC
PS:这次CCPC好难0.0慢慢学习吧。。
double ptos[100000];
double t=0.5;
void init()
{
ptos[0]=0;
ptos[1]=0;
ptos[2]=0;
ptos[3]=0;
ptos[4]=2;
for(int i=5; i<=maxn; i++)
{
if(i%4==0)
{
ptos[i]=ptos[i-1]+t+1+1;
t+=1;
}
else if(i%4==1)
{
ptos[i]=ptos[i-1]+t;
}
else if(i%4==2)
{
ptos[i]=ptos[i-1]+t+1;
}
else
{
ptos[i]=ptos[i-1]+t+1;
}
}
}
int main()
{
init();
//*
for(int i=4;i<=100;i++)
{
cout<<"i:"<<i<<" "<<ptos[i]<<endl;
}
//*/
// printf("%lf",ptos[9999]);//输出了几次发现9万多的时候面积才大于1e9,于是愉快的开了个10万数组
int T=0;
scanf("%d",&T);
while(T--)
{
ll n;
scanf("%I64d",&n);
int ans=0;
if(n<4)
{
if(n==0)
{
printf("0\n");
continue;
}
if(n==1)
{
printf("4\n");
continue;
}
if(n==2)
{
printf("4\n");
continue;
}
if(n==3)
{
printf("6\n");
continue;
}
}
else if(n<=1000&&n>=4)
{
for(int i=1; i<=100; i++)
{
if(ptos[i]>=n)
{
ans=i;
break;
}
}
printf("%d\n",ans);
}
else
{
ans=lower_bound(ptos,ptos+100000,n)-ptos;//二分
printf("%d\n",ans);
}
}
return 0;
}