zoukankan      html  css  js  c++  java
  • k倍区间 前缀和【蓝桥杯2017 C/C++ B组】

    标题: 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

    先求出每一位的前缀和并取余   那么任意区间[l,r]的和就可以通过sum[r]-sum[l-1]来得到

    要求区间和为k的倍数,即(sum[r]%k - sum[l-1])%k==0

    移项 sum[r] % k == sum[l-1] % k

    那么每两个对k取余得到值相同的sum 就可以组成一个k倍区间

    所以我们要统计下余数为0--k-1的前缀和个数

    取余为0的前缀和 说明[0,i]区间就已经存在一个k倍区间了   当然他还能跟另一个前缀和取余为0的[0,j]区间 组合成为[i,j]的k倍区间

    所以刚开始我们应该先把取余为0的个数加上

    然后对于所有取余相同的  两两配对能组成一个k倍区间,那么假设有x个取余相同的前缀和 那么他可以组成 ((x-1)*x)/2 个k倍区间     例如有 4个数 两两组合 3+2+1 = 3*(3-1)=6   

    其实是等差数列求和公式   n*(n+1)/2    不过这里的n = x-1; 

    #include<bits/stdc++.h>
    using namespace std;
    //int 只有85分 
    long long a[100005],sum[100005],num[100005];
    int main()
    {
        int n,k ;
        cin >> n >> k;
        for(int i = 0; i < n; i++){
          cin  >> a[i];
        }
        sum[0] = a[0]%k;
        for(int i = 1; i < n; i++){
          sum[i] = (sum[i-1]+a[i])%k; //求每个前缀和并趋于
        }
        memset(num,0,sizeof num);
        for(int i = 0; i < n; i++){
          num[sum[i]] ++;   // 统计余数为 0 -- k-1的个数
        }
        long long ans = num[0]; //能取余为0 自己本身就存在一个k倍区间了
        for(int i = 0; i < k; i++){
          ans += (num[i]*(num[i]-1))/2 ; //两两配对 等差数列 n*(n+1)/2   这里n=num[i]-1
        }
        cout << ans << endl;
    }
  • 相关阅读:
    icmp_ping学习笔记
    学习笔记
    解决Safari高版本浏览器中默认禁用第三方COOKIE(含demo)
    基础算法之插入排序Insertion Sort
    基础算法之选择排序Selection Sort
    基础算法之快速排序Quick Sort
    基础算法之冒泡排序Bubble Sort
    for语句嵌套循坏性能的剖析
    2014——>2015,我的薪资依然是4.5
    C# 反射浅析
  • 原文地址:https://www.cnblogs.com/llke/p/10780138.html
Copyright © 2011-2022 走看看