蓝桥杯2017 k倍区间 【前缀和】

本文介绍了一种高效算法,用于解决在给定数列中寻找所有子序列和为特定数值K倍数的问题。通过避免双重循环的遍历,利用前缀和与模运算的特性,实现了对大规模数据的有效处理。

问题描述
  给定一个长度为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

数据规模和约定
  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 2000ms
解题思路

       最简单的想法是两重for循环枚举所有区间,但是因为N能达到1e5,两重for就需要运算1e10,会超时。

      我们假设从第一个数开始到第i个数的和为 sum,sum%k == rare, 那么我们只要从第一个数到第i-1个数这个区间里减去一个从第一个数开始的连续的区间和%k = rare 的区间(假设这个区间为[ 1, j ] ),则sum - sum[1, j] 即区间[ j+1, i ]的和为k的整数倍。

      作法: 以数组cnt[p][i]记录区间[ 1, i ] 里区间和%k == p的从第一个数开始的连续区间的个数,以sum[ i ]记录前i个数的和,i从0到n枚举cnt[ sum[i]%k] [i-1]并加和即为所求的答案。 下面的代码是空间优化后的,为什么能优化? 自己考虑下。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
long long cnt[maxn];
int main()
{
	int n,k;
	cin >> n >> k;
	memset(cnt,0,sizeof cnt);
	long long tot=0,sum=0; 
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]); 
		sum += a[i];
		if(sum%k == 0)
			tot++;
		tot += cnt[sum%k];
		cnt[sum%k]++;
	}
	cout << tot << endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值