题目
给定一个长度为 N 的数列,A1,A2,⋯AN,如果其中一段连续的子序列 Ai,Ai+1,⋯Aj ( i ≤ j ) 之和是 K 的倍数,我们就称这个区间 [ i, j ] 是 K 倍区间,求出数列中总共有多少个 K 倍区间
输入:
5 2
1
2
3
4
5
输出:
6
思路
直接暴力枚举的会超时,所以要设置a数组,a[i]表示从第一项到第i项的数组之和,a[i]-a[j]就吧表示 i-j 区间,(a[i]-a[j])%K == 0表示K倍区间,那么等价于a[i]%K ==a[j]%K(注意i,j 表示的是从第一到第 i 或者 j的区间,与就是两个区间和的余数相等),那么其总共是统计所有余数相等的两个数的组合(高中数学, 然后加上单个的数
代码
#include <iostream>
using namespace std;
int main()
{
long long N,K,i,j,k;//使用long long防止溢出
long long cnt[100000] = {0};统计不同余数的多少
long count = 0;//k倍区间的和
long long a[100000] = {0};
cin>>N>>K;
for(i = 0;i < N;i++)
{
cin>>a[i]; // 输入
a[i] = (a[i-1] + a[i]);//表示从第一项到第i项的数组之和
cnt[a[i]%K]++;//统计不同余数的多少
}
for(i = 0;i < N;i++)
{
count = (cnt[i]*(cnt[i]-1))/2+count;//利用高中组合的公式
}
count = count+cnt[0];//加上单个的数
cout<<count;//输出
return 0;
}
- 总结:运用前缀和+组合数学的方法解决问题,也可以用暴力枚举(比赛的时候,当没有思路的时候可以先使用,拿到部分分数,之后再思考),重点是公式的推导和利用公式解决问题