AcWing——K倍区间

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

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

输入格式

第一行包含两个整数 NK

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

输出格式

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

数据范围

1≤N,K≤100000,

1≤Ai≤100000

输入样例:
5 2
1
2
3
4
5
输出样例:
6
题意:

求给定数列有多少个区间是k的倍数

分析:

因为是区间嘛,所以我开始的第一思路是先求出数列的去前缀和,然后枚举区间[i,j]是否满足条件,没想到居然超时了。

因此我们考虑如何进行优化。

首先,我们需要先知道几个点:

一:如果区间l~r 是k的倍数(sum[r]-sum[l-1])%k==0,那么sum[l-1]%k==sum[r]%k,

特别地,如果sum[i]%k==0,那么区间[1,i]是k的倍数

明白了这一点,我们就可以进行优化了。

首先,求出数组的前缀和取模,即sum[i]不再表示前缀和,而是前缀和的取模,意思是1~i的和%k

然后,用res[sum[i]]存储sum[i]出现的次数

最后,ans表示答案

具体这些变量的作用请看代码注释

#include <iostream>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int a[N],res[N],sum[N]; 
long long ans;
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;++i){
        cin>>a[i];
//sum[i]表示区间1~i的和模以k的值,用前一个模后的值加上a[i]可得到,具体证明就不给了
//如果不想这样子也可以先求前缀和,再单独对其取模,只不过这样的话数组得为long long
        sum[i]=(sum[i-1]+a[i])%k;
//res[sum[i]]表示sum[i]出现的次数,举个例子,如果sum[i]等于3,而res[sum[i]]=4,
//说明这次的3可以与前面4个三组合成k倍区间,那么ans就应该再加上4,之后res[sum[i]]就++
        ans+=res[sum[i]];
        res[sum[i]]++;
    }
//由于res[sum[i]]统计的是sum[i]相同的个数,如果res[sum[i]]==1是不加入答案的,但如果
//sum[i]==0,则自己可以成为k倍区间,故再加上res[0].
    ans+=res[0];
    cout<<ans;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值