前缀和-蓝桥杯省赛-K倍区间

前缀和-蓝桥杯省赛-K倍区间

题目:
给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。

你能求出数列中总共有多少个 K 倍区间吗?

输入格式
第一行包含两个整数 N 和 K。

以下 N 行每行包含一个整数 Ai。

输出格式
输出一个整数,代表 K 倍区间的数目。

数据范围
1≤N,K≤100000,
1≤Ai≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6

题意:
输 入 区 间 长 度 N , 整 数 K , 输入区间长度N,整数K, NK
输 入 N 个 数 , 问 长 度 为 N 的 区 间 中 , 有 多 少 个 子 区 间 的 区 间 和 是 K 的 倍 数 。 输入N个数,问长度为N的区间中,有多少个子区间的区间和是K的倍数。 NNK

题解:
对 区 间 和 问 题 的 处 理 , 考 虑 前 缀 和 。 对区间和问题的处理,考虑前缀和。

ll sum[N];//前缀和数组
ll ans=0;
for(int R=1;R<=N;R++)
	for(int L=1;L<=R;L++)
		if((sum[R]-sum[L-1])%K==0) ans++;

枚 举 区 间 的 左 右 端 点 L 和 R , 看 区 间 和 模 K 是 否 为 0 , 时 间 复 杂 度 O ( N 2 ) , T L E 。 枚举区间的左右端点L和R,看区间和模K是否为0,时间复杂度O(N^2),TLE。 LRK0O(N2)TLE
考 虑 能 否 优 化 掉 一 个 循 环 : 考虑能否优化掉一个循环:

事 实 上 , 第 二 层 循 环 是 计 算 : 前 R − 1 项 前 缀 和   当 中 与   前 R 项 和   同 余 的 个 数 事实上,第二层循环是计算:前R-1项前缀和\ 当中与\ 前R项和\ 同余的个数 R1  R 

所 以 我 们 开 一 个 c n t [ N ] 数 组 , 来 存 储 余 数 为 i 的 前 缀 和 的 个 数 所以我们开一个cnt[N]数组,来存储余数为i的前缀和的个数 cnt[N]i

每 枚 举 一 个 R , 答 案 就 加 上 c n t [ s u m [ R ] % K ] ( 表 示 在 前 R − 1 项 和 中 余 数 为 s u m [ R ] % K 的 个 数 ) , 再 更 新 c n t [ s u m [ R ] % K ] + + , 表 示 当 前 枚 举 的 第 R 项 前 缀 和 。 每枚举一个R,答案就加上cnt[sum[R]\%K](表示在前R-1项和中余数为sum[R]\%K的个数),\\再更新cnt[sum[R]\%K]++,表示当前枚举的第R项前缀和。 Rcnt[sum[R]%K](R1sum[R]%K)cnt[sum[R]%K]++R

时 间 复 杂 度 O ( N ) 。 时间复杂度O(N)。 O(N)

for(int i=1;i<=N;i++)
    {
        ans+=cnt[sum[i]%K];
        cnt[sum[i]%K]++;
    }

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int N,K;
ll cnt[maxn];//cnt[i]表示余数为i的数的个数
ll sum[maxn];
ll ans;
int main()
{
    cin>>N>>K;
    for(int i=1;i<=N;i++)//边读入边计算前缀和数组,因为原数组在后来不需要使用
    {
        scanf("%lld",&sum[i]);
        sum[i]+=sum[i-1];
    }

    cnt[0]=1;///初始状态下,区间和为0的sum[0]已有1个
    for(int i=1;i<=N;i++)
    {
        ans+=cnt[sum[i]%K];
        cnt[sum[i]%K]++;
    }

    printf("%lld\n",ans);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值