第八届蓝桥杯--K倍区间

 首先,科普一个数学知识

  • 若a%k==b%k,则|a-b|%k==0

所以,这一题我们可以用前缀和,结合这个数学知识解决

假设数列的前缀和用s存储

若s[i]%k==s[j]%k(i<j),则(s[j]-s[i])%k==0,所以a[i+1]~a[j]就是一个k倍区间

那么,在枚举到某个数s[j]时,我们怎么知道它前面出现的所有的i的个数,使得s[i]%k==s[j]%k呢,我们可以用一个数组存储,每次枚举,使cnt[s[i]%k]++;

  • 注意:枚举我们可以从0开始,这样的话,cnt[0]初始时就为1,每次枚举到s[i]%k==0的状态时,我们加上cnt[0],就多加了一个1,正好就是a[i]本身了,只有一个元素的K倍区间

C++代码如下:

#include<iostream>
using namespace std;
const int N=100010;
typedef long long LL;//开Long long 防止爆int
int n,k;
int a[N];
LL s[N];//前缀和数组
int cnt[N];
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
    LL res=0;
    for(int i=0;i<=n;i++){
        int t=s[i]%k;
        res+=cnt[t];//先加再给cnt[t]+1,不然就把自己也算上了
        cnt[t]++;
    }
    cout<<res<<endl;
    return 0;
}

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值