k倍区间(详解)

 

题目描述

给定一个长度为 NN 的数列,A_1, A_2, \cdots A_NA1​,A2​,⋯AN​,如果其中一段连续的子序列 A_i,A_i+1, \cdots A_jAi​,Ai​+1,⋯Aj​ ( i \leq ji≤j ) 之和是 KK 的倍数,我们就称这个区间 [i, j][i,j] 是 K 倍区间。

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

输入描述

第一行包含两个整数 NN 和 KK( 1 \leq N,K \leq 10^51≤N,K≤105 )。

以下 N 行每行包含一个整数 A_iAi​ ( 1 \leq A_i \leq 10^51≤Ai​≤105 )

输出描述

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

输入输出样例

示例

输入

5 2
1
2
3
4
5

输出

6

 

//k的倍数==前缀和的相同余数之差的总共情况+前缀和本身的情况.

//思路:前缀和+余数相等,前缀余数相等时,相减前缀就能得到有效的k倍区间
//(因为他们余数相等,相减的时候恰好将他们的余数消去可以把前缀比作
//nk+mod,mod是/k后留下的余数,nk1+mod-(nk2+mod),相减就只留下k。
#include <iostream>
using namespace std;
int main()
{
  int n,k,a;
  cin>>n>>k;
  long long sum=0,ans=0;
  //当前前缀和      总共情况
  int mod[100000];//统计余数相同时的次数

mod[0]=1;//初始化余数为0时余数记为1是因为余数为0时
//自己本身这个区间也算k的倍数,所以要多1,本身这种情况只有1次
//所以只加1,而后与其他余数相同,余数==0时前缀和相减也是一种情况.
for(int i=1;i<n;i++)
{
  mod[i]=0;
}//自身情况不算所以初始值为0
  for(int i=0;i<n;i++)
  {
    cin>>a;
    sum+=a;//每次都扩大1次前缀
    ans+=mod[sum%k];
    //对前缀取余,加上前面相同余数的情况,
    //相当于直接得到相减的步骤,
    //即当前的前缀减去前面所有相同余数前缀的结果
    //这里都是前缀相减的结果,不包含自身前缀本身
    //只有mod[0]时才是自身情况也算上
    mod[sum%k]++;
    //加上这一次的前缀的余数情况.

  }
  cout<<ans;//记得输出结果,调试如果只是答案错误但是什么输出都没有就表示你没打印结果!
  //一定要注意,不然白做!
  return 0;
}
//取余+相减==k的倍数,所以倍数题目一般都用取余
//如果不清楚自己的结论是否正确,可以自己写测试数据检测一下或者
//列举简单的数字看看结果是否相符,来判断是否程序正确或健全.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值