Kotlin练习 B. Integers Shop

理解题目
这个题目一大障碍应该是理解题目,毕竟咱们的老妈不说英语。。。
题目的意思是这样的:
假设我们有一个整数商店,这个商店的商品是一个个的整数区间(线段), 比如线段[2,4]代表打包出售数字[2, 3, 4], 同理[7,8]代表打包出售[7,8], 每个线段都一个价格C, 同时商店推出优惠活动,你购买了[2,4]和[7,8], 那么你现在拥有了数字[2, 3, 4, 7, 8] 商店会赠送你礼物数字5, 和6 赠送规则如下:
没有买x。
买了一个小于x的整数l。
买了大于x的整数r。
说白了就是中间缺的都会免费给你补上形成新的连续线段。
那么做为顾客,我们的目标是:

  1. 首先保证买到尽可能多的数字
  2. 在保证1的情况下花尽可能少的钱

但现在商店由于技术原因, 上架的n个线段只有前s个可供出售
所以说顾客只能在前s个线段中选择购买哪些

现在练习编码意图如下:
输入支持:
第一行输入一个数字 t 表明你要进行几次试验
然后就是进行t次试验的数据输入,其中每次试验需要输入如下数据
第一行输入商店总共有多少条线段出售n
然后循环输入每一条线段的参数 l, r, c一行代表一个线段(l起点, r终点, c售价)
注意,题目中对参数有值域限定,编程中应有所体现
讲道理我们大多数时候都是在做各种限定,各种检测,异常处理,真正的算法其实没多少东西,甚至说很简单。
值域限定容易理解,虽然写起来挺啰嗦的,其中一条我理解的未必准确
It is guaranteed that the total sum of n over all test cases doesn't exceed 2⋅10^5
这是英文,我理解的是所有输入的n的总和不超过2*10^5(实例代码有体现)

输出要求:
前边我们说了,在n个待售线段中由于技术原因只有前s个可供出售
那么输出方面就是让你分别设定这个s 从1-n, 然后给出在当前s值下,用户需要消费多少钱买到最多的数字
举例来说 假设当前商店出售的n=2个线段 分别为[1,4] 20块钱 [7,8] 30块钱,那么你应该输出
20//s=1时能买到1,2, 3, 4
50//s=2时能买到1, 2, 3, 4...8
好了题目说清楚了,再说说算法
首先我们必须在不考虑价格情况下找出能买到的最多的数字,那就找到s个线段中最小和最大的数字
有了这两个数字,根据贪心原理 在找到拥有最小数字最便宜的线段 和拥有最大数字最便宜的线段,这俩个价格相加即为我们最终消费(如果是同一个线段则无需加了)
那么算法和环境输入输出条件都有了, 剩下就是具体编码练习了,本例输出是固定的,所以错就是错,对就是对.
有兴趣的同学可以和c代码比较下,看看哪个更简洁明了
具体编码

import kotlin.math.pow

/**
 * Accomplished using the EduTools plugin by JetBrains https://plugins.jetbrains.com/plugin/10081-edutools
 *
 * To modify the template, go to Preferences -> Editor -> File and Code Templates -> Other
 */
/**
 * 线段数据类
 * 并且为了方便写了一个扩展函数
 */
data class Segment(val l:Long, val r:Long, val c:Long){
    fun checkValid(){
        val range = 1..1E9.toLong()
        check(l in range)
        check(r in range)
        check(c in range)
        check(r >= l)
    }
}
fun List<Long>.toSegment()= run {
    check(this.size==3)
    Segment(this[0], this[1], this[2]).also {it.checkValid()}
}

/**
 * 读取一个线段类
 */
fun readSegment() = readLine()!!
    .split(' ')
    .map { it.toLong() }
    .toSegment()
fun main() {
    // Write your solution here
    // 输入支持
    // 输入实验次数
    val t = readLine()!!.toInt()
    check(t in 1..1_000)//值域检测

    //循环读取各个实验的数据
    val inputs = (1..t).map {
        val n = readLine()!!.toLong()
        check(n in 1..1E5.toLong())
        //循环读取线段数据
        (1..n).map {
            readSegment()
        }
    }
    //n 的总是不能超过2*10^5检测
    check(inputs.sumOf { it.size }<=2E5)

    // 上面这一堆代码实际上都是在满足练习题的输入要求
    // 包括各种检测,具体算法其实简单的一B
    for(segments in inputs){
        (1..segments.size).map {s->
            segments.subList(0, s).run {
                //找出最小和最大的整数
                val minInt = minOf { it.l }
                val maxInt = maxOf { it.r }
                //找到拥有最小整数并且售价最低的segment
                val segWithMin = this.filter { it.l == minInt }
                    .minByOrNull { it.c }

                //同理找到max
                val segWithMax = this.filter { it.r == maxInt }
                    .minByOrNull { it.c }
                
                //输出结果
                if(segWithMax!!.l != minInt && segWithMax != segWithMin){
                    println(segWithMax!!.c + segWithMin!!.c)
                }
                else{
                    println(segWithMax!!.c)
                }
            }
        }

    }

}

如果确实阅读了这个代码,我们会发现算法的代码就那么几行,剩下的全是输入输出和各种检测。 虽然这是练习题,但我看这很符合实际开发的情况,当然实际开发中会更复杂一些, 现在仅仅是调用了个check函数而已,实际肯定要做处理的。

和前边一样, 那我们在思考一下 上述代码还有没有什么好的改进意见?
很遗憾,本人没想到太好的优化策略,最多也就是多加个条件判断提前退一下循环。意义不大。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容