蓝桥杯-k倍区间(C++)

蓝桥杯--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
资源约定
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms

我的思路

  1. 首先想的肯定是两个for循环,累加的和取模,若整除,则cnt++,最后输出cnt;但是肯定会超时,尽管蓝桥杯被称为暴力杯,但也不是这么暴力的。
  2. 之后看到各位大牛写的博客,我明白了
  3. 应该先在输入数的同时将前i项和用 sum[i] 记录下来,接下来要求的就是若 sum[i-j]%k==0,则++cnt,但如果仅仅这样也是n^2,也会超时。这时有一个绝妙的思路 ;
    sum[i-j]%k ==0 就是 sum[i]%k ==sum[j]%k
    就是用两个 sum[i] 与 sum[j] 除以k的余数 是否相等 来判断 [j-i]是否为k倍区间。
  4. 此时若用 数组cnt[ sum[i]%k ] (初始值为0)来记录 与 sum[i]%k 余数相同的其他sum的个数,也就是有多少个k倍区间。例如

当(n ==4,k ==2) a[]={1,2,3,4}
sum[[1]]=1 余数为1,此时cnt[[1]]==0.
sum[[2]]=3 余数为1,此时cnt[[1]] ==1,有sum[2-1]%k ==0即表示存在一个区间[2,2]为k倍区间。
sum[[3]]=6 余数为0,此时cnt[[0]]==0.
sum[[4]]=10 余数为0,此时cnt[[0]]==1,有sum[4-3]%k ==0即表示存在一个区间[4,4]为k倍区间。

  1. 此时再一遍for循环,temp+=cnt[i],得到结果temp为2.但实际应该为4. 因为我们忽略了当 cnt[0]时 就是表示前i项和 区间[i-1]就是为k倍区间,故还得 temp+=cnt[0].

代码展示

#include <iostream>
#include <string>
#include <string.h>
#include <algorithm>
#include <queue>
#include <set>
typedef long long ll;
using namespace std;
const int maxn=100005;
ll sum[maxn],a[maxn],cnt[maxn];
ll temp=0;
int n,k;
int main(){
    memset(sum,0,sizeof(sum));
    memset(cnt,0,sizeof(cnt));
    cin>>n>>k;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        sum[i]=sum[i-1]+a[i]; //先记录下前i项和
        temp += cnt[sum[i]%k];
        cnt[sum[i]%k]++;
    }
    cout<<temp+cnt[0]<<endl;
    return 0;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值