笔试算法-编程练习-01-Z-21

j这套题,比较灵活,更多的考验思维的敏捷性。

一、子串长度

题目描述

有一个仅包含’a’和’b’两种字符的字符串s,长度为n,每次操作可以把一个字符做一次转换(把一个’a’设置为’b’,或者把一个’b’置成’a’);但是操作的次数有上限m,问在有限的操作数范围内,能够得到最大连续的相同字符的子串的长度是多少。
输入描述:
第一行两个整数 n , m (1<=m<=n<=50000),第二行为长度为n且只包含’a’和’b’的字符串s。
输出描述:
输出在操作次数不超过 m 的情况下,能够得到的 最大连续 全’a’子串或全’b’子串的长度。
示例1
输入:
8 1
aabaabaa
输出:
5
说明:
把第一个 ‘b’ 或者第二个 ‘b’ 置成 ‘a’,可得到长度为 5 的全 ‘a’ 子串。

解析:

我们可以分别考虑,将a替换为b和将b替换为a的情况。以a替换为b为例,若想产生最长的字串,那么必须要将连续m个a替换为b,那么我们只需要遍历所有情况即可。

在实际计算中,我们可以保存所有a的索引,并且在首尾添加-1和n作为边界,我们若将前m个a变为b,则该次变化所产生的子串长度为length=p_a[m+1]-p_a[-1]-1,以此循环即可。

代码:

import sys

def calc(s, m, n):
    result = 0
    p_a = [-1]
    p_b = [-1]
    for idx in range(len(s)):
        if s[idx] == 'a':
            p_a.append(idx)
        else:
            p_b.append(idx)
    
    p_a.append(n)
    p_b.append(n)
    len_a = len(p_a)
    len_b = len(p_b)
    if m >= len_a-1 or m >= len_b-1:
        return n
    
    # idx 表示当前没有被改变的字母
    for idx in range(m+1, len_a):
        result = max(result, p_a[idx]-p_a[idx-m-1]-1)
    
    for idx in range(m+1, len_b):
        result = max(result, p_b[idx]-p_b[idx-m-1]-1)
    
    return result   

in_ = input().split()
n, m = int(in_[0]), int(in_[1])
s = input().split()[0]
print(calc(s, m, n))

二、房间传送门

题目描述:

存在n+1个房间,每个房间依次为房间1 2,3.1,每个房间都存在一个传送门,i房间的传送门可以把人传送到房间pi(1<=pi<=),现在路人甲从房间1开始出发(当前房间1即第一次访问),每次移动他有两种移动策略:A.如果访问过当前房间ì偶数次,那么下一次移动到房间i+1;B.如果访问过当前房间i奇数次,那么移动到房间pi; 现在路人甲想知道移动到房间n+1一共需要多少次移动;
输入描述
第一行包括一个数字n(30%数据1<=n<=100,100%数据1<=n<=1000),表示房间的数量,接下来一行存在n个数字 pi(1<=pi<=i,pi表示从房间i河可以传送到房间pi.
输出描述
输出一行数字,表示最终移动的次数,最终结果需要对1000000007(10e9+7)取模

解析:

一维动规,对于f(n+1) = 2*(f(n)+1) - f(pi[n])

代码:

import sys

n = int(input().split()[0])
in_ = input().split()
p_i = [0]
c_i = [0]
for _ in in_:
    p_i.append(int(_))
    c_i.append(0)

result = [0]*(n+2)
result[1] = 0
for idx in range(2, n+2):
    result[idx] = 2*(result[idx-1]+1)-result[p_i[idx-1]]

print(result[n+1])

三、球队比分

题目描述:

有三只球以,每只球队编号分别为球队1,球队2,球以3,这三只球以一共需要进行n场比赛,现在已经踢完了长场比赛,每场比赛不能打平,跟赢一场比赛得一分,输了不得分不减分,已知球队1和球队2的比分相差d1分,球队2和球队3的比分相差d2分,每场比赛可以任意选择两只队伍进行,求如果打完最后的(n-K)场比赛,有没有可能三只球队的分数打平。
输入描述
第一行包含一个数字t(1 <=t<= 10)接下来的t行每行包括四个数字 n,k,d1, d2(1 <= n<= 10^12;0 <= k<= n,0 <= d1, d2 <= k)输出描述
每行的比分数据,最终三只球队若能够打平,则输出“yes”,否则输出“no“

解析:

由于输了不扣分,因此剩余场次(n-k)-需要消除的分差(abs(d1)+abs(d2))需要大于0,且是偶数,这样才能保证在清空分差后不会产生新的分差

代码:

import sys

__ = int(input().split()[0])
for _ in range(__):
    temp = input().split()
    n, k, d1, d2 = int(temp[0]), int(temp[1]), int(temp[2]), int(temp[2])
    temp = n-k-abs(d1)-abs(d2)
    if temp >= 0 and temp % 2 == 0:
        print('yes')
    else:
        print('no')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值