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')