【前缀和+取余】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


#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
typedef long double ld;
const ll maxn = 1e5+100;
const ll mod = 1e9+7;
const ld pi = acos(-1.0);
const ll inf = 1e18;

ll n,k,arr[maxn],pre[maxn],ans,num[maxn]; 

int main()
{
    ios::sync_with_stdio(false);
	
	cin >> n >> k;
	
	for(ll i = 1; i <= n; i++)
	{
		cin >> arr[i];
		pre[i] = ( pre[i-1]+arr[i] )%k;
		
		if(pre[i] == 0)  //从1-n的和对k取余为0 
			ans++;
	}
	
	for(ll i = 1; i <= n; i++)
	{
		
		ans += num[ pre[i] ];  // 到i这个位置前面有多少个与pre[i]相等的数 
		num[ pre[i] ]++;   
	}
	
	cout << ans << endl;
	
	return 0;
}

 

### 关于2017年蓝桥杯竞赛中的“k区间”问题 #### 问题描述 给定一个数组 `arr` 和正整数 `k`,找出所有子区间的数量,使得这些子区间的元素之和能够被 `k` 整除。 --- #### 解题思路分析 此问题的核心在于利用 **前缀和** 的概念来优化计算效率。以下是详细的解题方法: 1. 定义前缀和数组 `prefix_sum[i]` 表示从数组起始位置到第 `i` 个位置的累加和,则有: \[ prefix\_sum[i] = arr[0] + arr[1] + ... + arr[i-1] \] 2. 对于任意两个索引 \(x\) 和 \(y\) (\(x < y\)),如果满足条件: \[ (prefix\_sum[y] - prefix\_sum[x]) \% k == 0 \] 则说明该区间 `[x+1, y]` 是一个合法的 “k 区间”。 3. 将上述公式变形可得: \[ prefix\_sum[y] \% k == prefix\_sum[x] \% k \] 这意味着只需统计具有相同数的前缀和的数量即可快速找到符合条件的区间数目[^1]。 4. 使用哈希表记录每种可能的数值及其对应的出现次数,在遍历过程中动态更新并累计计数器变量的结果值。 5. 特殊情况处理:当某个前缀和本身就能被 `k` 整除时也需要计入结果之中;因此初始化哈希表时应设置键为零的情况初始频次设为一。 ```python def count_k_multiple_subarrays(nums, k): from collections import defaultdict mod_count = defaultdict(int) mod_count[0] += 1 # 初始化特殊情况 total = result = 0 for num in nums: total += num remainder = total % k if remainder < 0: # 处理负数模 remainder += k result += mod_count[remainder] mod_count[remainder] += 1 return result ``` 以上代码实现了基于前缀和与同性质高效解决 K 区间问题的方法[^2]。 --- #### 时间复杂度与空间复杂度 - **时间复杂度**: O(n),其中 n 是输入数组长度。因为仅需一次线性扫描整个列表。 - **空间复杂度**: O(k),用于存储最多 k 种不同数的状态信息。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值