首页 > 其他分享 >前缀和与差分

前缀和与差分

时间:2023-04-07 13:47:40浏览次数:40  
标签:前缀 int 差分 iff 哈希 区间 include

1. K倍区间

来源:第八届蓝桥杯省赛C++B组,第八届蓝桥杯省赛JAVAB组
原题链接

题目描述

给定一个长度为 \(N\) 的数列,\(A_1,A_2,…A_N\),如果其中一段连续的子序列 \(A_i,A_{i+1},…A_j\) 之和是 \(K\) 的倍数,我们就称这个区间 \([i,j]\) 是 \(K\) 倍区间。

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

输入格式

第一行包含两个整数 \(N\) 和 \(K\)。

以下 \(N\) 行每行包含一个整数 \(A_i\)。

输出格式

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

数据范围

\(1≤N,K≤100000\),
\(1≤A_i≤100000\)

输入样例

5 2
1
2
3
4
5

输出样例

6

算法:(前缀和 + 哈希表)\(O(n)\)

算法内容

  • 暴力做法:
    我们先预处理前缀和,用\(i\)和\(j\)暴力枚举所有区间,每一次判断区间[j, i]是否满足\((s[i] - s[j - 1])\) % \(k\) \(=\) \(0\),若满足答案加\(1\),但是会循环\(\frac{n^2}{2}\)次,时间复杂度为\(n^2\),会TLE

  • 我们如何优化?
    我们可以只用\(i\)枚举区间的右端点,对于所有以\(i\)为右端点的区间我们要找的是\(i\)前面有多少数满足:
    \(s[i] - s[i - 1]\) % \(k\) \(=\) \(0\) \(\iff\) \(s[i]\) % \(k\) \(=\) \(s[i - 1]\) % \(k\)
    \(s[i] - s[i - 2]\) % \(k\) \(=\) \(0\) \(\iff\) \(s[i]\) % \(k\) \(=\) \(s[i - 2]\) % \(k\)
    \(s[i] - s[i - 3]\) % \(k\) \(=\) \(0\) \(\iff\) \(s[i]\) % \(k\) \(=\) \(s[i - 3]\) % \(k\)
    ···
    \(s[i] - s[0]\) % \(k\) \(=\) \(0\) \(\iff\) \(s[i]\) % \(k\) \(=\) \(s[0]\) % \(k\)
    问题转化为s[i]前面有多少个数满足它除以\(k\)的余数是\(s[i]\) % \(k\),所以我们可以用哈希表记录s数组中\(i\)前面的所有的数除以\(k\)的每一种余数的出现次数,每一次循环查表\(s[i]\) % \(k\)的次数,并累加,然后更新哈希表。

  • 注意:
    1.答案最多为\(\frac{n^2}{2}\)个,可能爆\(int\);前缀和数组最大的值可能为\(N*K\)个,也可能爆\(int\)
    2.最开始循环时,\(i = 1\),一定记得将\(s[0]\)的信息插到哈希表中,因为\(s[0] = 0\),所以\(s[0]\) % \(k\) \(=\) \(0\),出现\(1\)次
    3.每一次循环结束记得把\(s[i]\)的信息加到哈希表中


C++代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int n, k;
LL s[N], cnt[N];

int main()
{
    scanf("%d%d", &n, &k);
    
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%lld", &s[i]);
        s[i] += s[i - 1];
    }

    LL res = 0;
    cnt[0] = 1; //一定要初始化是前面的s0的信息,因为s0 = 0,所以s0 % k = 0出现一次
    for (int i = 1; i <= n; i ++ )
    {
        res += cnt[s[i] % k];
        cnt[s[i] % k] ++ ;
    }

    printf("%lld\n", res);

    return 0;
}

标签:前缀,int,差分,iff,哈希,区间,include
From: https://www.cnblogs.com/lhycoder/p/17295865.html

相关文章

  • 前缀和-leetcode303
    LeetCode上的题目"303.区域和检索-数组不可变",是一个相对简单的问题。问题描述:给定一个整数数组nums,求出该数组从索引i到j(i≤j)范围内元素的总和,包含i,j两点。实现NumArray类:NumArray(int[]nums)用整数数组nums初始化对象intsumRange(inti,intj)返回......
  • js用前缀名查找class或id节点,js模糊查询某个dom节点
    js在操作dom的场景中,有时候会有类似的场景需求。js用前缀名查找class节点//参数dom为htmldom节点//参数key为需模糊查询的名称字段functionqueryClassNode(dom,key){letcollectArray=[];for(vari=0;i<dom.childNodes.length;i++){ //核心点......
  • 用前缀树实现中文敏感词过滤器
    前言本文代码实现一个中文的敏感词过滤器,预先将准备好的敏感词写入前缀树数据结构中实现快速检索,并且节省内存。一般用于检查注册用户名称、言论是否包含不文明的词汇。可以判断内容是否包含敏感词;找出内容中的敏感词;将内容中的敏感词替换成设置的字符。运行环境代码使用了JDK......
  • 前缀和
    [acwing]4405.统计子矩阵#include<cstdio>usingnamespacestd;typedeflonglongLL;constintN=510;intn,m,k;ints[N][N];LLres;intmain(){scanf("%d%d%d",&n,&m,&k);for(inti=1;i<=n;i++)......
  • 咬咬龟对前缀和的反对
    咬咬龟对前缀和的反对在计算机科学中,前缀和(PrefixSum)是一种常见的算法技术,用于高效地处理数组或序列中某一区间内元素的和。然而,在最近的一次直播中,国内知名主播咬咬龟表达了他对前缀和算法的反对意见,引发了广泛的讨论和争议。咬咬龟指出,前缀和算法虽然在某些情况下可以提高算......
  • 【LBLD】小而美的算法技巧:前缀和数组
    【LBLD】小而美的算法技巧:前缀和数组一维数组中的前缀和classNumArray{private:vector<int>preSum;public:NumArray(vector<int>&nums){preSum.push_back(0);for(inti=1;i<nums.size()+1;i++){preSum.push_back(......
  • 基于matlab的多符号差分球形译码误码率仿真
    1.算法描述    球形译码的基本思想是在以一个矢量x为中心的半径为d的多维球内搜索格点,通过限制或者减少搜索半径从而减少搜索的点数,进而使得计算时间减少。球形译码算法带来的优点在于它不需要象传统的最大似然译码算法那样需要在整个格内对所有的格点进行搜索,而只需要在......
  • 前缀和和差分
    前缀和和差分前缀和#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<vector>#include<cstring>#include<unordered_set>#include<set>#include<stack>#include<map&g......
  • 双因素方差分析流程
    双因素方差分析流程一、案例分析当前收集了39名志愿者减重效果的相关数据,他们的生活方式可分为3种,现在研究人员想要研究生活方式和性别对于减重的影响,想要知道不同的生......
  • LeetCode 周赛 338,贪心 / 埃氏筛 / 欧氏线性筛 / 前缀和 / 二分查找 / 拓扑排序
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。大家好,我是小彭。上周末是LeetCode第338场周赛,你参加了吗?这场周赛覆盖的知识点很多,第四题......