k倍区间--蓝桥杯

该博客介绍了如何利用前缀和与取余运算的性质解决寻找数列中K倍区间的算法问题。通过计算每个位置的数列元素对K取余的值,并用cnt数组记录每个余数值出现的次数,可以发现当两个前缀和的余数值相同时,它们之间的区间即为K倍区间。博主提供了详细的解题思路和简化后的代码实现,将问题转化为排列组合问题,最终输出满足条件的区间数量。
摘要由CSDN通过智能技术生成

评测地址:https://www.lanqiao.cn/problems/97/learning/

一、问题描述
给定一个长度为N的数列,A1, A2, … AN,如果其中一段连续的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。
  你能求出数列中总共有多少个K倍区间吗?
输入格式
  第一行包含两个整数N和K。(1 <= N, K <= 100000)
  以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)
输出格式
  输出一个整数,代表K倍区间的数目。
样例输入
5 2
1
2
3
4
5
样例输出
6
数据规模和约定
  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 2000ms

思路:
首先这道题很大可能会是一道数学题,只要找到相应的思路应该可以轻易上手。
其次题目又与区间求和有关所以很容易联想到前缀和所以我们使用sum[ ]存放前缀和。
我们设区间和sumi表示前 i 项的和则区间 [ i, j ]的和可以表示为sum[ j ] - sum[ i - 1 ],所以如果( sum[ j ] - sum[ i - 1 ] ) % k == 0那么就说明这个区间是题目中所说的 “ k倍区间 "。如果看到这里那么你离正确解法就只差捅破最后的窗户纸了!!
根据取余运算规则(a-b)%p=(a % p - b % p) % p,那么上面的判定条件就可以转换为 sum[i - 1] % k == sum[j] % k!!!发现了么?这说明只要满足两个前缀和取余后的余数相同就能组成一个 “ k倍区间 ”。举个例子:
序列:1、2 、3、4、5(假设 mod == 2)
前缀和:1、3、6、10、15
余数:1、1、0、0、1
这时候我们任选两个余数相同的即可组成一个 “ k倍区间 ”。
?这不就是排列组合的问题么,这时我们只要将余数使用cnt[]数组存放起来,计数之后就只剩下排列组合的问题了。
好了我们现在基本已经得到了这道题的思路了。
注意要用long long哦~
还有就是sum[]数组可以简化为sum变量。(自行体会)
(思路比代码长系列)

#include<iostream>
#include<cstring>
using namespace std;
#define maxn 100005
typedef long long LL;
LL cnt[maxn];
LL n, k, num, ans = 0, sum = 0;
int main() {
    cin >> n >> k;
    memset(cnt, 0, sizeof(cnt));
    cnt[0] = 1;
    for (int i = 1; i <= n; i++) {
        cin >> num;
        sum += num;
        cnt[sum % k]++;
    }
    for (int i = 0; i < k; i++)
        ans += cnt[i] * (cnt[i] - 1) / 2;

    cout << ans;
    return 0;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值