[蓝桥杯][2017年第八届真题]k倍区间
时间限制: 1Sec 内存限制: 128MB 提交: 671 解决: 158
题目描述
给定一个长度为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
题干要求我们求得是k的倍数区间,我们可以用s[i]储存前i个数,用s[i]-s[j-1]表示区间【j,i】的和。然后我们利用两层for循环枚举区间范围,寻找符合要求的区间。至此,问题似乎解决了,But题干所给的数据范围是1e5,双层循环肯定会超时,那么怎么办呢?我们来分析一下问题,题干让我们寻找的是满足(s[i]-s[j-1])%k= =0的情况,上述算法之所以会超时,原因在于需要枚举i,j的范围,那么我们是否换种思路。即求s[i]%k= =s[j-1]%k的情况有多少。因为求s[i]%k= =s[j-1]%k的情况并不需要进行枚举,只需把s[i]%=k储存 桶排序 最后再加上这个数本身就是k的倍数的情况即可。
代码如下:
#include <stdio.h>
long long a[100005],s[100005],v[100005],n,k,ans,temp; //满足条件 (s[r]-s[l-1])%k==0 即(s[r]%k)==(s[i-1]%k) 则符合条件
int main()
{
scanf("%lld%lld",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%lld",&temp);
s[i]=(s[i-1]+temp)%k;
ans+=v[s[i]];
v[s[i]]++;
}
ans+=v[0];
printf("%lld",ans);
return 0;
}