zoukankan      html  css  js  c++  java
  • [蓝桥杯训练] 第八届(2017)省赛 C/C++ A组 T09

    1. 题目

    标题: 分巧克力

    儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
    小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

    为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

    1. 形状是正方形,边长是整数
    2. 大小相同

    例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。

    当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?

    输入
    第一行包含两个整数N和K。(1 <= N, K <= 100000)
    以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
    输入保证每位小朋友至少能获得一块1x1的巧克力。

    输出
    输出切出的正方形巧克力最大可能的边长。

    样例输入:
    2 10
    6 5
    5 6

    样例输出:
    2

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms


    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意:
    main函数需要返回0;
    只使用ANSI C/ANSI C++ 标准;
    不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include <xxx>
    不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    2. 分析

    2.1 如何理解题意

    一个x*y的巧克力能分多少块正方形出来,这其实是很简单的问题。我们很容易发现:

    ①对于一个矩形,能分离的最大的正方形的变长取决于该矩形最小的边长。

    ②在①的基础上,缩小边长能分出更多的巧克力,但他们拼起来肯定不会超过最大的那个正方形。

    我们还是用图来解释,假设有一个2*3的巧克力:

    那么能分出最大的巧克力显然是2*2,也就是2*3中最短边“2”作为边长的正方形,再往下分,1*1的巧克力显然是基于原本最大的2*2正方形分割而来的。

    进而,我们能很容易的发现,对任意x*y的巧克力,能够分出边长为i的正方形的小巧克力的数量为:(x/i)*(y/i),这里利用整型除法向下取整的特性。举个例子,5*6的巧克力,当i=2时,一共能分出(5/2)*(6/2)=2*3=6块巧克力;i=3时,一共能分出(5/3)*(6/3)=1*2=2块巧克力。

    2.2 怎么选取最大的巧克力边长

    输入n组数据,每组有两个边长,那么根据我们上面的结论,只需要做一个for循环,并使i从1至maxShortSide,其中maxShortSide就是在n组数据中最大的短边。

    那么,我们只需对每一个i,分别对n组数据(巧克力)计算可以分出的总数量并相加,若大于k则符合要求并记录,然后再使i++,若此时不能满足总数大于k,则上一个i就是能分出来的最大边长的巧克力。这里注意的是,只要总数大于k就可以停止相加,即使程序还未遍历n组数据。这样的设计可以优化时间量度,避免TLE。

    3. 程序

     1 #include <iostream>
     2 #include <sstream>
     3 #include <algorithm>
     4 #include <vector>
     5 #include <set>
     6 #include <list>
     7 #include <string>
     8 #include <map>
     9 #include <cmath>
    10 #include <cstring>
    11 #include <cstdlib>
    12 #include <fstream>
    13 using namespace std;
    14 
    15 #define DEBUG 1  //DEBUG为1,则需要在第23行更改输入的文件名
    16 
    17 
    18 int main() {
    19     set<string> st;
    20     long n, k;
    21     long currentMax=0, maxShortSide=0;   //int类型也行,看题目的规模
    22 #if DEBUG
    23     ifstream fin( "in7.txt" ,ios::in);
    24     fin >> n >> k;
    25 #else    
    26     cin >> n >> k;
    27 #endif
    28     long chocolate[n][2];  
    29     for (int i=0; i<n; i++) {
    30 #if DEBUG
    31         fin >> chocolate[i][0] >> chocolate[i][1];  //从文件导入测试数据
    32 #else
    33         cin >> chocolate[i][0] >> chocolate[i][1];  //控制台输入数据
    34 #endif        
    35         if (maxShortSide < min(chocolate[i][0],chocolate[i][1])) {
    36             maxShortSide = min(chocolate[i][0],chocolate[i][1]);  //寻找maxShortSide的值
    37         }
    38     }
    39     for (long i=1; i<=maxShortSide; i++) {
    40         int sum = 0;
    41         for (long j=0; j<n; j++) {
    42             sum+= (chocolate[j][0]/i) * (chocolate[j][1]/i); //求出本块巧克力能被分解成多少块边长为i的正方形小巧克力,并于前面的数量相加
    43             if (sum >= k) break;  //若相加后大于小朋友的数量k,则直接退出循环,因为数量已经满足题目需求
    44         }
    45         if (sum >= k && i > currentMax) { //当总数大于小朋友数量且新的i比旧的cunrrentMax还要大,则更新currentMax
    46             currentMax = i;
    47         }
    48         else if (sum < k) {   //另一处优化,节省时间,当某个i值无法满足k的要求时,大于i的值自然也无法满足,直接break
    49             break;
    50         }
    51     }
    52     cout << currentMax;  //输出结果
    53     return 0;
    54 }

    4. 运行结果

    时间明显少于限制时间,故未记录运行时间

  • 相关阅读:
    Linux 定时任务
    VIM快速使用
    ulimit 命令
    PG语句
    linux下的PGSQL安装步骤
    linux下安装mysql 5.5和5.6.32
    linux下安装达梦数据库(DM8)x86版本
    redis配置
    sql server 2008安装
    linux下安装部署oracle
  • 原文地址:https://www.cnblogs.com/sser-invincible/p/8624837.html
Copyright © 2011-2022 走看看