[蓝桥杯][2017年第八届真题]k倍区间 (前缀和)

[蓝桥杯][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;
}
发布了31 篇原创文章 · 获赞 11 · 访问量 2574

猜你喜欢

转载自blog.csdn.net/guyjy/article/details/105001137