[蓝桥杯 2017 省 B] k 倍区间
题目描述
给定一个长度为 N N N 的数列, A 1 , A 2 , ⋯ A N A_1,A_2, \cdots A_N A1,A2,⋯AN,如果其中一段连续的子序列 A i , A i + 1 , ⋯ A j ( i ≤ j ) A_i,A_{i+1}, \cdots A_j(i \le j) Ai,Ai+1,⋯Aj(i≤j) 之和是 K K K 的倍数,我们就称这个区间 [ i , j ] [i,j] [i,j] 是 K K K 倍区间。
你能求出数列中总共有多少个 K K K 倍区间吗?
输入格式
第一行包含两个整数 N N N 和 K K K ( 1 ≤ N , K ≤ 1 0 5 ) (1 \le N,K \le 10^5) (1≤N,K≤105)。
以下 N N N 行每行包含一个整数 A i A_i Ai ( 1 ≤ A i ≤ 1 0 5 ) (1 \le A_i \le 10^5) (1≤Ai≤105)。
输出格式
输出一个整数,代表 K K K 倍区间的数目。
样例 #1
样例输入 #1
5 2
1
2
3
4
5
样例输出 #1
6
提示
时限 2 秒, 256M。蓝桥杯 2017 年第八届
code:
#include<iostream>
using namespace std;
const int N=100010;
int n,k;
long long s[N];
int cnt[N];
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>s[i];
s[i]+=s[i-1];
}
cnt[0]=1;//s[0]
long long res=0;
for(int i=1;i<=n;i++){
res+=cnt[s[i]%k];
cnt[s[i]%k]++;
}
cout<<res;
return 0;
}
//s[i]%k和s[i-1]%k的余数如果相等,那么sum[i]-sum[i-1]的差值必然是k的倍数
//解释下 ans+=res[sum[i]];
//首先明确 res[sum[i]] 表示的是sum[i]出现过的次数。
//举个例子,假设 sum[i] = 3,在后边的循环中,又出现了一个 sum[i] = 3,那么此时,这个“3”可以和前边出现过的所有的“3”分别构成一个K倍区间,前边的“3”一共出现过res[sum[i]] 次,所以 此时又新增了res[sum[i]]个K倍区间。