算法练习题12---蓝桥杯2017省赛“k倍区间”

文章目录

  • 一、题目描述
      • 输入:
      • 输出描述
      • 运行限制
  • 二、思路
  • 三、具体代码


# 前言

蓝桥杯2017省赛,编程题(C++)

一、题目描述

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

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

输入:

第一行包含两个整数 N 和 K( 1≤N,K≤10的五次方 )

以下 N 行每行包含一个整数Ai ( 1≤Ai≤10的五次方)

输出描述

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

示例输入:

5 2
1
2
3
4
5

示例输出:

6

运行限制

  • 最大运行时间:2s
  • 最大运行内存: 256M

二、思路

如果采用纯暴力搜索,需要三个for循环,必定会超时,那么可以考虑通过以下几步来进行优化,以减小时间复杂度。

  • 首先,可以采用前缀和的思想,在输入Ai的过程中,就将前缀和求出,然后后续需要判断区间时,比如[i,j] 之间是否是k的倍数,我们就可以直接用A[j]-A[i-1]来求出i~j之间的累加和,单步操作的时间复杂度为O(1),相比于之前每次求和都需要的O(n),明显快出很多。

  • 比较坑的一点,前缀和的数组一定要采用long long或更大的数据类型,int型是无法通过的

  • 有了前缀和的优化,时间还是会超时,这个时候就要从整除即模K这个点去设法优化。按照题目的意思,对于(A[j]-A[i-1])%K == 0即为符合要求,这一步可以再分解为A[j] %K==A[i-1] %K,这样写出来,我们题目的条件也就变成了先要寻找有多少个在模K结果相同下的数据,然后再求出同样模K结果下这些数据的组合方式。

  • 比如我们有5组相同的模K数据,那么对应的可能取值就为4+3+2+1+0,这里简单画一个图,就很容易理解

    算法练习题12---蓝桥杯2017省赛“k倍区间”_第1张图片
  • 最后一个要注意的就是,模K等于0的情况,这个模K等于0,说明正好能整除K,那么是可以独立成组的,所以最后答案需要加上模K为0的个数

三、具体代码

#include
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    long long a[100030]={0};
    long long b[100030]={0};
    long long c[100030]={0};  //c中存放在该一余数下,共有多少个相同值
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[i]+=a[i-1];
        b[i]=a[i]%k;  //存放累加和后对k取余的结果
    }
    for(int i=1;i<=n;i++)
    {
        ans+=c[b[i]];  //这里实现了0+1+2+3+...这样的过程
        c[b[i]]++;    //统计同一余数下的个数
    }
    ans+=c[0];  //看看余数为0的个数,这些是可以独立成为一种情况
    cout<<ans<<endl;
    return 0;
}

你可能感兴趣的:(算法,算法,蓝桥杯,概率论)