题目
问题描述
给定一个长度为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
方法:前缀和 取模
代码
#include<iostream>
#include<algorithm>
using namespace std;
long long input[100010],show[100010];
int main()
{
int n,k,tp;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>tp;
input[i]=(input[i-1]+tp)%k;
show[input[i]]++;
}
long long ans=0;
for(int i=0;i<k;i++) //0<i<k 因为mod k之后最大是k-1
ans+=show[i]*(show[i]-1)/2;
cout<<ans+show[0];
return 0;
}
注意点
1 每次都取模然后求前缀和,简化计算
2 用一个show数组存放前缀和
1 2 3 4 5的前缀和为 1 1 0 0 1 那么show[0]=2,show[1]=3;
show数组从0到k-1 因为mod k之后最大是k-1
3 在存放完前缀和后就需要计算结果了
我们需要注意到 前缀和相同的两个位置i,j (比如示例中的1和5两个数字),
那么(i,j] 这个位置区间内的数字是k倍区间(2 3 4 5这些数字是k倍区间)
也就是说任意两个前缀和相等的位置可以组成一个k倍区间
那么就好办了 我们已经通过show数组记录了各种前缀和的数量
只要计算之和就可以了
还需要加上前缀和等于0的那些数量 得到结果
4 可能讲的大家听不太明白 我就按示例演示一遍吧
5 2
1 2 3 4 5
可以求得前缀和数组 input[1]=1 input[2]=1 input[3]=0 input[4]=0 input[5]=1
然后我们得到前缀和结果数组show[0]=2 show[1]=3;
也就是说前缀和等于0的有2个 等于1的有3个
然后看等于1的这些位置 1 2 5
那么可以看出这三个位置任意选两个组合,他们中间的数之和就是前缀和
(1和2 中间(i,j] 也就是2 ; 1和5中间(i,j] 也就是2345 ; 2和5 中间也就是345 )
所以我们得到结论 从每种前缀和中任取两个都是k倍区间
那么怎么计算呢 其实就是排列组合
然后我们注意到这样计算完之后ans=4,这是因为我们少了show[0]的区间;