蓝桥杯真题k倍区间详解//看了解答包你会

今天做了2道题都叫k倍区间,一个是2022年的,一个是2017年

下面我来说说2017年的这道题,稍微简单一点

1:所有余数的重要性:实际上,代码在处理时并不只关注余数为 0 的情况。所有的余数都被考虑进去了。关键在于理解“余数相同”的两个前缀和之间的子数组和能被 m 整除的原理

2余数相同的前缀和:当两个不同的前缀和 a[i] 和 a[j](假设 i < j)对 m 取余后的结果相同,即 a[i]%m == a[j]%m,这意味着从 i+1 到 j 的子数组和可以被 m 整除。这是因为 a[j] - a[i](即子数组 i+1 到 j 的和)能够被 m 整除。

3为什么所有余数都计算在内当遍历到数组的第 j 个元素时,代码通过查看 cnt[a[j]%m] 来确定之前有多少个前缀和与 a[j] 的余数相同。这个计数包括了所有可能的余数值,而不仅仅是 0。因此,每当你找到两个前缀和的余数相同,你就找到了一个其和能够被 m 整除的子数组。

4:res 的累加过程:因此,当 res 被累加时,它实际上包含了所有可能的余数情况,不仅仅是余数为 0 的情况。cnt[a[i]%m] 的值被加到 res 时,这代表着所有以第 i 个元素结尾,且和能被 m 整除的子数组的数量。

5:避免非 0 余数的干扰:你可能会问,为什么这不会错误地包括那些和不能被 m 整除的子数组?关键在于,我们只是在计算以特定余数结束的子数组数量。只有当我们找到另一个具有相同余数的前缀和时,这两个前缀和之间的差(即一个子数组的和)才会被计算为能够被 m 整除。这意味着我们实际上没有直接计算那些和不能被 m 整除的子数组;我们只是通过比较余数来找到那些可以形成和能被 m 整除的子数组的前缀和。

总结来说,代码通过比较所有前缀和的余数,有效地计算出了所有和能被 m 整除的子数组数量。这种方法巧妙地利用了模运算的性质,确保了每一种余数情况都被考虑在内,而不会受到其他余数的干扰。

看到这里我相信你还是有点不清楚,看看代码,然后在看我后面的解答

#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5;
using ll=long long;
ll a[N];
ll b[N];//用来求前缀和a的
ll cnt[N];//用来计数的//看到后面就明白了//统计余数的个数
int main(){
  cnt[0]=1;//这点很重要//这个是特殊的第一次为0就说明可以除尽了的
  int n;cin>>n;
  int k;cin>>k;//倍数
  for(int i=1;i<=n;++i){
    cin>>a[i];
  }
  for(int i=1;i<=n;++i){
    b[i]=b[i-1]+a[i];//前缀和
  }
  long long ans=0;//统计答案的
  for(int i=1;i<=n;++i){
    ans+=cnt[b[i]%k];
    cnt[b[i]%k]++;
  }
  cout<<ans;
  return 0;
}

现在我来跟大家说说看为什么会这样??

首先大家看见过后仔细看了过后肯定会有一个疑惑??ans加的时候不是会把其他b[i]%k!=0的情况也加进来吗

而且在后面cnt数组也会把出现余数的个数慢慢直接整加1//ans不是会把其他的情况也统计进去吗

这点我先开始在做的时候也是有这个问题的????

现在我就来说说为什么ans在加的时候不会被其他的情况所影响,而且为什么cnt[0]=1??其他的情况都为0

其实我们不一定是要找余数为0的情况//而是把所有的情况都考虑进去了的//大家理解一下这句话//

余数相同的2个前缀和之间的子数组能被m整除//这个原理理解一下

看到这里大家应该还是有问题//当后面余数出现奇数次的时候不会被多加吗//当没有找到余数相等的时候也会加进去的吗

这点也就是cnt其他的时候都为0,只有cnt[0]=1这个余数等于1

现在我说不管后面余数出现几次//只要不是第一次出现(0除外)都没有影响//都会与前面那次出现余数相等的i构成被k整除的数组

举个例子来说,假设某个前缀和 a[5] 对 k 取余数的结果与之前某个前缀和 a[3] 对 k 取余数的结果相同,

那么从位置 4 到位置 5 的子数组的和一定能被 k 整除。即使后面再出现相同余数的前缀和,它们也都会与之前的形成子数组和能被 k 整除的区间。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值