KickStart 2020-Round-A python版解题

前言

第一次接触kick start,先刷了几轮体验一下,好久没有做类似的编程题目,不太会做了...
暂时使用Python编程,后续也会用C++再实现一遍。

RoundA 地址https://codingcompetitions.withgoogle.com/kickstart/round/

Round A

1. Allocation

有 n 套房子出售。买第一栋房子花了A_i美元。你有一个 B 美元的预算可以花。你最多能买多少套房子?
输入
输入的第一行给出了测试用例的数量,接下来是 T,T 测试用例。每个测试用例都以包含两个整数 N 和 B 的单行开始。第二行包含 N 个整数。A_i,第i个房子的成本。

题解:分配问题,将单价进行升序排序,然后从小到大用B购买即可。(注:kick start不提供输入输出处理,需要自己对输入和输出进行标准化处理)

T=input()
for i in range(int(T)):
    _=input().split(' ')
    N=int(_[0])
    B=int(_[1])
    As=input().split(' ')
    As=[int(_) for _ in As]
    As.sort()
    res=0
    for a in As:
        if a <= B:
            res+=1
            B-=a
        if B<=0:
            break
    print('Case #{}: {}'.format(i+1,res)) 

2. Plates

有 N堆盘子。每个堆包含 K个 盘。每个盘子都有一个正值,描述它看起来是多么美丽。现在需要P个 盘子做晚餐。如果他想在一堆中拿一个盘子,他也必须在那堆中拿上面的所有盘子。挑选美丽值总和最大的P个盘子。
输入
每个测试用例都以包含三个整数 N,K 和 P 的一行开始,然后是 N行。第 i 行包含 K 个整数,从上到下描述每一堆里盘子的美丽值。

题解:整个问题可以描述成下图的情况,将盘子进行分配;从N*K中按照规则选取P个盘子,可以用动态规划的方法来实现

按照动态规划的思路,我们需要建立基本的动态规划公式,对应dp[i][j],dp[N][K]就是最后要的结果。

分析过程如下
T=int(input())
for i in range(T):
    N,K,P=[int(_) for _ in input().split(' ')]
    Ns=[]
    res=0
    for _ in range(N):
        Ns.append([int(_) for _ in input().split(' ')])
    _sum=[]
    _sum.append([0 for _ in range(K)])
    for _ in Ns:
        _tmp=[]
        _tmp.append(0)
        for idx,x in enumerate(_):
            if not idx:
                _tmp.append(x)
            else:
                _tmp.append(x+_tmp[-1])
        _sum.append(_tmp)
    res=[[0 for _ in range(P+1)] for _ in range(N+1)]
    for n in range(1,N+1):
        for p in range(P+1):
            for x in range(0,min(K,p)+1):
                res[n][p]=max(res[n][p],_sum[n][x]+res[n-1][p-x])
        
    print('Case #{}: {}'.format(i+1,res[N][P]))

3. WorkOut

给定N个递增的正整数,然后向数组中插入K个正整数使得数组仍然递增,同时达到数组相邻元素差值最小;求插入后两个相邻元素差值的最大值是多少。

题解:题目的意思可以用下面一张图来表示,通过插入K个值使得数组相邻差值的最大值最小化

结果所需的最优差值
d_{best}
必然出现在
1 ,max(Delta_i)
间,且满足相应的划分总次数不超过K,(若需要把区间长度为
Delta_i
的间隔分成最优差值
d_{best}
,需要
ceil(Delta_i/d_{best})-1
个值插入)。

线性搜索最优差值就可以得到目标结果,但时间复杂度较高,会超时;因此可以尝试二分搜索,从1 ,max(Delta_i)中找出最优差值,检验当前差值是否都符合划分次数的限制要求即可,时间复杂度明显下降。

import math
T=int(input())

for t in range(T):
    N,K=[int(_) for _ in input().split(' ')]
    ts=[int(_) for _ in input().split(' ')] 
    delta=[]
    for i,_ in enumerate(ts):
        if not i:
            continue
        delta.append(_-ts[i-1])
    def check(t):
        _sum=[]
        for _ in delta:
            _sum.append(math.ceil(_/t)-1)
        return sum(_sum)<=K

    max_d=max(delta)
    left=1
    right=max_d
    _ans=0
    while left<=right:
        mid=(left+right)//2
        if check(mid):
            right=mid-1
            _ans=mid
        else:
            left=mid+1
 
    print('Case #{}: {}'.format(t+1,_ans))
             
 

4. Bundling

给定N个字符串,把其分配到大小为K的多个组里(K能整除N);每个串仅能划分到某一个组里面,且这个组的得分就等于该组所有字符串的最长公共前缀的长度。求划分后各组最大分数和。

The score of a group is equal to the length of the longest prefix shared by all the strings in that group. For example:The group {RAINBOW, RANK, RANDOM, RANK} has a score of 2 (the longest prefix is 'RA').
The group {ALLOCATION, PLATE, WORKOUT, BUNDLING} has a score of 0 (the longest prefix is '').

题解 可以看出这个题与最长公共前缀有关,可以使用字典树来辅助解题,将N个字符串用字典树进行表示,自根而下,每个节点对应一个字符,每个节点可以保存一个前缀重复数量,即有多少个字符串有相同的前缀(从根节点到当前节点),字典树的形式如下图所示

同时,这个题目还符合贪心算法的思想,即计算最长公共前缀对应的分值就能得到最后的最大分值;公共前缀长度为
x
,对应重复的字符串为
l
,相应分值计算为
x*(l//K)
,对字典树,从最长公共前缀节点往根节点进行遍历,减去已经使用的
(l//K)*K
个字符串,再进行相应的分值计算,直至遍历完整个字典树,即可得到对该字典树的所有字符串的最大得分。

我们在具体实现时,按照递归的思路实现了下面的公式,在完整测试集上出现了递归超层的RuntimeError的错误。

from collections import defaultdict
class Char_Tree():
    def __init__(self):
        self.root={}
        self.root.setdefault('num',0)
        self.end='#'
    
    def insert(self,word):
        node=self.root
        for char in word:
            node=node.setdefault(char,{})
            node.setdefault('num',0)
            node['num']+=1
        node[self.end]=None

T=int(input())
for t in range(T):
    N,K=[int(_) for _ in input().split(' ')]
    str_list=[]
    for _ in range(N):
        str_list.append(input())
    predix=[]
    ct=Char_Tree()
    for _ in str_list:
        ct.insert(_)
    def travel(tree,step,_sum,ans ):
        for _ in tree:
            if _=='num' or _=='#':
                continue
            if tree:
                s,ans=travel(tree[_],step+1,0,ans)
                _sum+=s
        #print('tree',tree)
        tmp=(tree['num']-_sum)/K
        if tmp:
            ans+= tmp*step
            _sum+=tmp*K
        return _sum,ans
    _,ans=travel(ct.root,0,0,0)
    print('Case #{}: {}'.format(t+1,ans))

继而做了简单的修改,在创建字典树的同时计算得分值,这是一种很简单巧妙的方法,建树的过程就是从根向下的过程,而得分与公共前缀长度即节点的深度相对应,因此,在添加节点的过程中就可以计算得分,每个节点都做s//K的操作,多个节点合起来就对应成上面提到的x*(l//K)的分数。

from collections import defaultdict
class Char_Tree():
    def __init__(self,K):
        self.root={}
        self.root.setdefault('num',0)
        self.end='#'
        self._sum=0
        self.K=K
    
    def insert(self,word):
        node=self.root
        for char in word:
            if char in node:
                node=node[char]
                self._sum-=node['num']//self.K
                #node.setdefault('num',0)
                node['num']+=1
                self._sum+=node['num']//self.K
            else:
                node=node.setdefault(char,{})
                node.setdefault('num',1)
                self._sum+=1//self.K
            
            
        #node[self.end]=None

T=int(input())
for t in range(T):
    N,K=[int(_) for _ in input().split(' ')]
    str_list=[]
    for _ in range(N):
        str_list.append(input())
    predix=[]
    ct=Char_Tree(K)
    for _ in str_list:
        ct.insert(_)
    print('Case #{}: {}'.format(t+1,ct._sum))

END

本人简书所有文章均为原创,欢迎转载,请注明文章出处: //www.greatytc.com/p/61876e60403d。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问本人简书主页查看最新信息//www.greatytc.com/u/40d14973d97c

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

推荐阅读更多精彩内容