[Luogu P4274] [BZOJ 1505] [NOI2004]小H的小屋

洛谷传送门
BZOJ传送门

题目描述

小 H 发誓要做 21 21 21 世纪最伟大的数学家。他认为,做数学家与做歌星一样,第一步要作好包装,不然本事再大也推不出去。为此他决定先在自己的住所上下功夫,让人一看就知道里面住着一个“未来的大数学家”。

为了描述方便,我们以向东为 x x x 轴正方向,向北为 y y y 轴正方向,建立平面直角坐标系。小 H 的小屋东西长为 100 100 100Hil(Hil 是小 H 自己使用的长度单位,至于怎样折合成 m m m,谁也不知道)。东墙和西墙均平行于 y y y 轴,北墙和南墙分别是斜率为 k 1 k_1 k1 k 2 k_2 k2 的直线, k 1 k_1 k1 k 2 k_2 k2 为正实数。北墙和南墙的墙角处有很多块草坪,每块草坪都是一个矩形,矩形的每条边都平行于坐标轴。相邻两块草坪的接触点恰好在墙上,接触点的横坐标被称为它所在墙的“分点”,这些分点必须是 1 1 1 99 99 99 的整数。

小 H 认为,对称与不对称性的结合才能充分体现“数学美”。因此,在北墙角要有 m m m 块草坪,在南墙角要有 n n n 块草坪,并约定 m ≤ n m \leq n mn。如果记北墙和南墙的分点集合分别为 X 1 X_1 X1 X 2 X_2 X2,则应满足 X 1 ⊆ X 2 X_1 \subseteq X_2 X1X2,即北墙的任何一个分点一定是南墙的分点。

由于小 H 目前还没有丰厚的收入,他必须把草坪的造价降到最低,即草坪 的占地总面积最小。你能编程帮他解决这个难题吗?

输入输出格式

输入格式:

仅一行,包含 4 4 4 个数 k 1 k_1 k1 k 2 k_2 k2 m m m n n n k 1 k_1 k1 k 2 k_2 k2 为正实数,分别表示北墙和南墙的斜率,精确到小数点后第一位。 m m m n n n 为正整数,分别表示北墙角和南墙角的草坪的块数。

输出格式:

一个实数,表示草坪的最小占地总面积。精确到小数点后第一位。

输入输出样例

输入样例#1:
0.5 0.2 2 4
输出样例#1:
3000.0

说明

QQ20180304215637.png【约定】

  • 2 ≤ m ≤ n ≤ 100 2 \leq m \leq n \leq 100 2mn100
  • 南北墙距离很远,不会出现南墙草坪和北墙草坪重叠的情况

解题分析

贪心地想, 想要最小化面积, 肯定就要均分上下的边长。 所以我们可以先将北墙划分为两个部分: 左边的一部分有 m − n   m o d   m m-n\ mod\ m mn mod m块, 每块对应的南墙数量为 ⌊ n m ⌋ \lfloor\frac{n}{m}\rfloor mn, 右边的一部分有 n   m o d   m n\ mod\ m n mod m块, 每块对应的南墙数量为 ⌊ n m ⌋ + 1 \lfloor\frac{n}{m}\rfloor+1 mn+1

然后我们发现 n , m n,m n,m范围很小, 可以直接枚举左边一部分分配到的大小, 暴力 c h e c k check check即可。 当然, 还是需要均分长度的, 按照类似上面的步骤分配即可。 由不等式易证这个面积是单峰的, 所以我们只要 c h e c k check check到一个位置, 其面积比之前大, 就可以 b r e a k break break了。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define db double
db k1, k2, ans = 1e25;
int up, down, lef, rig, lblk, rblk;
template <class T> IN T sqr(T a) {return a * a;}
IN db calc(R int blk, R int len, db rat)
{
    if(!blk) return 0;
    int llen, rlen, lnum, rnum;
    llen = len / blk, rlen = llen + 1;//类似划分为两个部分
    rnum = len % blk, lnum = blk - rnum;
    return sqr(llen) * rat * lnum + sqr(rlen) * rat * rnum;
}
void solve()
{
    db buf;
    if(!(down % up)) return printf("%.1lf", calc(lef, 100, k1) + calc(lef * lblk, 100, k2)), void();//如果可以除尽直接平均划分就好
    R int bd = 100 - rig * rblk;
    for (R int arr = lblk * lef; arr <= bd; ++arr)
    {
        if(ans > (buf = calc(lef, arr, k1) + calc(rig, 100 - arr, k1) + calc(lblk * lef, arr, k2) + calc(rblk * rig, 100 - arr, k2)))
        ans = buf;
        else break;
    }
    printf("%.1lf", ans);
}
int main(void)
{
    scanf("%lf%lf%d%d", &k1, &k2, &up, &down);
    rig = down % up; lef = up - rig;
    lblk = down / up, rblk = down / up + 1;
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值