【刷题日记】网易——瞌睡

题目:瞌睡

小易觉得高数课太无聊了,决定睡觉。不过他对课上的一些内容挺感兴趣,所以希望你在老师讲到有趣的部分的时候叫醒他一下。你知道了小易对一堂课每分钟知识点的感兴趣程度,并以分数量化,以及他在这堂课上每分钟是否会睡着,你可以叫醒他一次,这会使得他在接下来的k分钟内保持清醒。你需要选择一种方案最大化小易这堂课听到的知识点分值。

输入描述:

第一行 n, k (1 <= n, k <= 105) ,表示这堂课持续多少分钟,以及叫醒小易一次使他能够保持清醒的时间。
第二行 n 个数,a1, a2, … , an(1 <= ai <= 104) 表示小易对每分钟知识点的感兴趣评分。
第三行 n 个数,t1, t2, … , tn 表示每分钟小易是否清醒, 1表示清醒。

输出描述:

小易这堂课听到的知识点的最大兴趣值。

输入例子1:

6 3
1 3 5 2 5 4
1 1 0 1 0 0

输出例子1:

16

最初写了两层暴力循环,计算在不同时间叫醒的兴趣评分

import sys
line1 = sys.stdin.readline().split()
line1 = list(map(int, line1))
n, k = line1[0], line1[1]

a = sys.stdin.readline().split()
a = list(map(int, a))

t = sys.stdin.readline().split()
t = list(map(int, t))

knowledge = []
if k>=n:
    print(sum(a))
else:
    for i in range(n-k):
        grade = 0
        for j in range(i):
            if t[j] ==1:
                grade+=a[j]
        for j in range(i,i+k):
            grade += a[j]
        for j in range(i+k,len(a)):
            if t[j] == 1:
                grade +=a[j]
        knowledge.append(grade)
    print(max(knowledge))

结果…

您的代码已保存
运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为60.00%

那咋算呢,这回算 长度为k 的窗口内,叫醒比不叫醒增加的兴趣分吧。因为醒着的分数是固定的。分数能得到提升是因为叫醒增加的。找到叫醒增加最多的就好了

import sys
line1 = sys.stdin.readline().split()
line1 = list(map(int, line1))
n, k = line1[0], line1[1]

a = sys.stdin.readline().split()
a = list(map(int, a))

t = sys.stdin.readline().split()
t = list(map(int, t))

# 醒着的得分
base_score =0
for i in range(n):
    base_score += a[i]*t[i]

# 叫醒增益
gain = 0
if k >= n:
    print(sum(a))
else:
    for i in range(n):
        # 找到叫醒的点
        g = 0
        if t[i] ==0:
            # 开始计算叫醒的增益
            for j in range(i,min(i+k,n)):
                if t[j] ==0:
                    g+=a[j]
        if g>gain:
            gain = g
    print(gain+base_score)

结果…比上次进步了一点点:

运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为80.00%

所以算法的问题是太慢了。。 O ( n 2 ) O(n^2) O(n2)肯定是不行的。。
接下来想办法写 O ( n ) O(n) O(n)
牛客上讨论的一个答案是这样的, 这个和下面的答案意思差不多。但下面那个更简洁好懂一些。

nk = list(map(int,input().split()))
n = nk[0]
k = nk[1]
a = list(map(int,input().split()))
t = list(map(int,input().split()))
 
max = 0 #记录前k个瞌睡叫醒后兴趣的最大值
for i in range(k):
    if(t[i]==0):
        max += a[i]
 
pos = 0 #记录最大值的位置
pre = 0 #记录窗口移动过程中最后一个元素位置( 应该是窗口最前面的一个元素的位置,就是移动就要被淘汰的元素)
cur = max  #当前窗口内的兴趣值

for i in range(k,n):
    if(t[pre]==0):  #元素过期  前一个叫醒点
        cur -= a[pre] # 当前窗口减去淘汰值
    if(t[i]==0): # 新的叫醒点
        cur += a[i]  #当前窗口加入新的值
    pre += 1 # 窗口后移了一位
    if(cur>max): # 更新最大值
        max=cur
        pos=i
 
sum=0  #记录清醒状态下的和
for i in range(n):
    if(t[i]==1):
        sum+=a[i]
print(sum+max)

(出于规范,建议不要用sum,和max做变量名吧)

下面这个代码比较好懂!

n, k = list(map(int, input().strip().split()))
a = list(map(int, input().strip().split()))
t = list(map(int, input().strip().split()))

base_score = 0
for i in range(n):
    if t[i]:
        base_score += a[i]
        a[i] = 0  # 计算完醒着的得分,把得分置为0,这样就不用费力气去找叫醒点。大小为k的窗口每次后移一个就好,醒着的值为0不影响
max_score = tmp = sum(a[:k])  # max_score记录叫醒增益。 tmp记录当前窗口的增益
for i in range(k, n):  # 第二个开始的窗口的末尾范围是 k~n-1
    tmp = tmp + a[i] - a[i - k] # 后移了一位,新窗口增益是 旧tmp + 新增的值a[i] - 过期的值a[i-k]
    max_score = max(max_score, tmp) # 如果右移一位增益变大,则更新max_score
ans = base_score + max_score # 最终得分就是醒着的得分加叫醒增益
print(ans)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值