【蓝桥杯真题--k倍区间】【蓝桥杯PythonB组备赛】【前缀和】非常详细且曲折的做题过程思路注释分享Python解

目录

蓝桥杯真题——k倍区间

1.题目描述

2.思路过程详细注释解析

3.最终代码实现


这道题做得太艰难了……我做了一晚上……

所以兄弟们,刚上手算法题可能都很艰难,大家不要放弃一起加油哇!


蓝桥杯真题——k倍区间

1.题目描述

 示例

输入:

5 2
1
2
3
4
5

输出:

6

 

2.思路过程详细注释解析

ps:非最终代码,运行会超时

"""
本题考点:前缀和 + 数学思维
    本题乍一看是考前缀和,
    但由于数据过大,所以还需做亿点优化。
    主要优化为:(数学技巧)发现余数和k倍区间的关系(详见后)
"""
N, K = map(int, input().split())
A = []
for _ in range(N):
    A.append(int(input()))
A_pre = [0]
for i in range(N):
    A_pre.append(A_pre[i] + A[i])
ans = 0
'''
今日get——思维转换:

当我们使用二重循环导致时间复杂度过大引起运行超时时,
很多情况下我们需要 多观察分析题目条件 ,
从 数学角度 上灵活优化代码,
而不是仅仅想着:
"二重循环太大了想办法弄成一重的"
一直死磕代码本身,可能并不会有成效
'''
# for i in range(0, N + 1):
#     for j in range(i + 1, N + 1):
#         if (A_pre[j] - A_pre[i]) % K == 0:
#             ans += 1
'''
# 数学技巧:发现余数和k倍区间的关系
    (A_pre[j] - A_pre[i]) % K == 0
 ==> A_pre[j] % K == A_pre[i] % K
 即:当 A[j]的前缀和的余数 == A[i]的前缀和的余数 时,
    区间[i, j]是K倍区间(ans += 1)
    
 因此,我们有了新的思路:
 1.求出所有前缀和的余数存入列表 A_pre_yu
 2.遍历列表A_pre_yu,两个余数相同的位置可以构成一个k倍区间
    相同余数个数  区间个数
    2             1
    3             2+1
    4             3+2+1
    ……
    可以发现,区间个数的运算满足等差数列求和
    (等差数列前n项和公式:Sn=n*a1+n(n-1)d/2或Sn=n(a1+an)/2)
    
    # 也可直接使用组合数公式:C(n, 2)
    # 可以这么想:比如相同的余数有4个,求区间个数。
    # 就是在问你:从4个人里挑2个出来唱歌,请问有几种组合方式?
    
    当有相同余数时,我们按照上述规律统计区间个数ans。
 3.A_pre_yu的第一个元素0刚好不影响结果,
   所以不需要额外考虑。
'''
A_pre_yu = [i % K for i in A_pre]
for i in range(K):
    cnt = A_pre_yu.count(i)  # 后期发现运行依旧超时,所以最终版会对此进行优化
    # ans += (cnt - 1) * (1 + (cnt - 1)) // 2  # 前n项和
    ans += (cnt - 1) * cnt // 2  # 组合数 C(n, 2)
print(ans)
# 此思路或非最优解,还请见谅

3.最终代码实现

"""
针对过程代码的两处改进:
1.优化对数列输入、前缀和及其余数的存储
2.优化count函数,改用列表存储余数个数
"""
N, K = map(int, input().split())
A_pre, ans = 0, 0
cnt_yu = [0] * K  # 存储余数的个数:下标是余数,值是余数个数
for _ in range(N):
    A_pre += int(input())
    cnt_yu[A_pre % K] += 1  # 对该余数个数+1
cnt_yu[0] += 1
for i in range(K):
    ans += cnt_yu[i] * (cnt_yu[i] - 1) // 2
print(ans)
# 此思路或非最优解,还请见谅

题解和分析是结合自己的认识以及参考各路大神的代码整理汇总出来的,供大家参考~

如有不足或不解之处欢迎留言指正哈。

如有帮助可以点赞收藏嘛,感谢~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头小二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值