Acwing-1230 K倍区间 (普通)-第八届蓝桥杯省赛C++ B组
输入样例:
5 2
1
2
3
4
5
输出样例:
6
样例理解:输入数组的元素个数,k为2,后面就是5个元素的数组
思路
思路
前缀和
直接上代码,不懂的再看后面的解释(自嗨)
//
// Created by 20116 on 2024/3/14.
//
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 100005;
int n, k, a[N], sum[N], res[N], ans = 0;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
sum[i] = (sum[i - 1] + a[i]) % k; // 前缀和取模
ans += res[sum[i]]; // 累加的是 不以开头的区间的k倍区间
res[sum[i]]++; // 统计摸相同的区间
}
cout << ans + res[0]; // 最后加上前缀和模为0的区间,也就是以原数组开头的区间
return 0;
}
举个栗子
1 2 3 4 5
前缀和后:
1 3 6 10 15
既然是k倍的区间,那就取模
1 1 0 0 1
模运算:发现右边的前缀和减去左边的前缀和就是中间的区间大小
然后进行取模
比如1-3,区间总和是1 + 3 + 6,取模就是0
2-5, 区间总和就是2的前缀和减去5的前缀和,也就是15 - 3 = 12
取模就是0,意味着2-5,就是k倍区间
再回来看数组的前缀和取模
1 1 0 0 1
发现第2和第5的前缀和取模的加起来再取模正是0,也就是2-5就是k倍区间
还有1-2,1-5,2-5,3-4是符合这个条件的
发现有点和最开始的k倍区间不太一致
实际上就是a-b区间内的区间也就是右边的减去左边的区间
比如1-2就是2,
1-5就是2-5
2-5就是3-5
3-4就是4
就是(x, y]的样子左开右闭区间
这就ok了,ok了吗,还有两个区间呢
那就是前缀和啦,所以就需要加上两个0了
有点不太理解啊
那就在数组前面加上一个0吧
也就是
0 1 1 0 0 1
发现了华点!
原来之前没有把第一个数字开始的区间给算进去了
所以在最后的结果加上了sum[0]了