这题目描述
给定一个长度为 N 的数列,A1,A2,⋯AN,如果其中一段连续的子序列 Ai,Ai+1,⋯Aj(i≤j) 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。
你能求出数列中总共有多少个 K 倍区间吗?
输入格式
第一行包含两个整数 N 和 K (1≤N,K≤105)。
以下 N 行每行包含一个整数 Ai (1≤Ai≤105)。
输出格式
输出一个整数,代表 K 倍区间的数目。
输入输出样例
输入 #1复制
5 2 1 2 3 4 5
输出 #1复制
6
说明/提示
时限 2 秒, 256M。蓝桥杯 2017 年第八届
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<long long> s(n + 1, 0); // 前缀和数组,使用long long避免溢出
for (int i = 1; i <= n; ++i) {
int a;
cin >> a;
s[i] = s[i - 1] + a;
}
vector<int> cnt(k, 0); // 余数统计数组,大小为k
cnt[0] = 1; // 初始余数0出现一次(对应s[0])
long long ans = 0;
for (int i = 1; i <= n; ++i) {
int mod = (s[i] % k + k) % k; // 确保余数为非负数
ans += cnt[mod]; // 累加当前余数已出现的次数
cnt[mod]++; // 更新余数出现次数
}
cout << ans << endl;
return 0;
}
这段代码众嘴难理解的就是利用哈希表记录
. 哈希表 cnt
的初始状态
-
初始化
cnt[0] = 1
,表示余数0
已出现一次(对应s[0] = 0
)。 -
余数相同的前缀和之差是K的倍数:
若s[j] % K = s[i] % K
,则s[j] - s[i]
是K的倍数,对应区间[i+1, j]
。 -
哈希表
cnt
的作用:
记录余数出现的次数,每次遇到相同余数时,直接累加已出现的次数作为新增区间数。 -
初始条件
cnt[0] = 1
:
确保前缀和本身为K倍数时(如s[i] % K = 0
),可以正确统计区间[1, i]
。
cnt[0]=1;
for(int i=1;i<=n;i++)
{
int mod=(s[i]%k+k)%k;
ans+=cnt[mod];
cnt[mod]++;
}