[NOIP模拟][好题]造盒子

题目描述:
企鹅豆豆收到了面积为 K 的一块橡皮泥。但是他没有合适的盒子来装下这个橡皮泥。所以他打算造一个盒子。
制造台是有方形网格的平台,每个小正方形边长为 1 。现在豆豆有两类木板,一类只能放在小正方形的边上,一类只能放在小正方形的对角线上。
现在豆豆想知道最少需要用多少块木板来制造一个封闭的盒子来把橡皮泥放下去。
输入格式:
第一行一个整数 T 表示数据组数。
对于每组数据的第一行一个整数 K ,表示橡皮泥的大小。
输出格式:
输出一个整数表示最少需要的木板数目
样例输入:
5
1
2
3
4
5
样例输出:
4
4
6
6
7
数据范围:
对于 50% 的数据, K20
对于 100% 的数据, K109
题目分析:
样例说明:k=5时这里写图片描述
这是一道规律题。如果能找到规律就十分简单了。
通过构图找规律:
因为同样是一块木板,对角线的木板明显更长,围成的面积也会更大,周长相同,越圆,面积越大。于是有当木板数i%4=0时,一个斜着放的正方形是最优的。如图:
这里写图片描述
i%4=1时,收到k=5的启发,我们向外拓展一个梯形。
这里写图片描述
i%4=2时,此时有两种想法,我们是从另外一边再扩展一个梯形,还是把原来的梯形扩展成一个长方形。如图,可以看出长方形是一个梯形的两倍多,所以选择长方形更优秀。
这里写图片描述
i%4=3时,此时当然是选择从最长边扩展出一个梯形。
这里写图片描述
图片来源:g19zwk的博客

我考试时并没有好好画图,而是奇葩地分析数据得出结论:

  • 块数   最大围住面积    与上一个差
  • 4    2
  • 5    2.5      0.5
  • 6    4       1.5
  • 7    5.5      1.5
  • 8    8
  • 9    9.5     1.5
  • 10   12      2.5
  • 11   14.5     2.5
  • 12  
    我们可以看出,i%4=0时,就是木板数除以4后的平方的两倍(相当于在计算一个正方形),而对于i%4=1是,就是比上一个多了i/4(整除)-0.5,i%4=2,i%4=3都是比上一个多了i/4+0.5。
    两种规律都可以求出答案。
    附代码:
    数据分析法代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<iomanip>
#include<cmath>
#include<cctype>
#include<algorithm>
using namespace std;

int po,t,k;
double ans[100100];

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

int main()
{
    freopen("area.in","r",stdin);
    freopen("area.out","w",stdout);

    for(int i=4;i<=100000;i++)
    {
        po=i/4;
        if(i%4==0) ans[i]=(i/4)*(i/4)*2;
        else
            if(i%4==1) ans[i]=ans[po*4]+po-0.5;
            else ans[i]=ans[po*4+1]+(i-po*4-1)*(po+0.5);
    }

    t=readint();
    while(t--)
    {
        k=readint();
        for(int i=4;i<=100000;i++)
            if(ans[i]>=k)
            {
                printf("%d\n",i);
                break;  
            }
    }

    return 0;
}

构图规律法:
此代码同样来源于:g19zwk

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

int T,k;
int s[92010];//因为询问是整数,所以省去了小数是没问题的

int main()
{
    freopen("area.in","r",stdin);
    freopen("area.out","w",stdout);

    s[4]=2;
    for(int i=5;i<=92000;++i)//预处理
    {
        if(i%4==0)
            s[i]=(i/4)*(i/4)*2;
        if(i%4==1)
            s[i]=s[i-1]+((i-1)/4+(i-1)/4-1)/2;
        if(i%4==2)
            s[i]=s[i-2]+(i-2)/2;
        if(i%4==3)
            s[i]=s[i-1]+((i-3)/4+1+(i-3)/4)/2;
    }

    T=getint();
    while(T--)//直接查询
    {
        k=getint();
        for(int i=4;i<=92000;++i)
            if(s[i]>=k)
            {
                cout<<i<<'\n';
                break;
            }
    }

    return 0;
}
发布了99 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qianguch/article/details/78208223