前缀和【截断区间】【k倍区间】

【截断区间】

  • 介绍:给定长度为n的数组,将该数组从中间截断 , 得到三个非空子数组,要求这三个子数组内各元素之和相等
  • 做法 : 一开始想用双指针来做,但是发现如果一个一个指两个指针的变化都非常大,所以用双指针不行,然后就开始会考虑前缀和,我们把这个数组的前缀和求出来,既然是需要三个区间,而且每个区间的和都是一样的,那么我们就要找到这个满足三分之一和三分之二和的位置在哪里
int solution(int q[] ,int sum , int n ){
	int j = 0;
	for(int i = 0 ; i < n  - 1; i++){
	//n - 1是因为指针不能指到头部否则无法形成一个区间
		tot += q[i];
		if( sum / 3 * 2 == tot){
			ans += j ; //满足三分之二的区间加上前面满足三分之一和的区间的个数,也是一个组合
		}
		if(tot == sum / 3){
			j ++;//找到了满足三分之一和的一个位置,区间个数加1
		}
	return ans;
}			 

【k倍区间】

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

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

  • 想法: 如果想用双指针一个指向头部一个指向尾部,从最开始的元素开始求他的前缀和,然后遍历前缀和数组,找到能被k整除的个数,这么做确实很容易想到,但是这个题目的数据量是 1 0 5 10^5 105如果每次求完前缀和再减去头元素在遍历求k倍的前缀和,那么时间复杂度最大可能进行 1 0 10 10^{10} 1010,肯定是超时的,所以需要想一个更巧妙的办法

  • 做法:比如说给的样例 : 1 2 3 4 5

  • 我们求他的前缀和: 1 3 6 10 15

  • 要求他的2倍区间,我们抛弃想法中的做法,我们可以吧前缀和的元素,都对k取余数那么我们会得到一个新的数组

  • 新的数组为:1 1 0 0 1

  • 既然和是k倍的,我们发现满足取余为0的都是符合条件的(比如说我们可以找到一个满足条件的区间[1,2,3])对于1的来说怎么看呢,满足1的都是除不断的,我们可以这么想,同时存在两个1会发生什么呢,是的如果说1号位置取余是1,2号位置取余是1,那会发生什么呢😋,对了,就是说2号位置是满足条件的。于此我们可以说,只要有两对或者两对以上的非零数存在,那么两个非0的且相同的数就可以构成一个符合条件的k倍区间。在这里我们有3个位置取余为1,分别是1号位置,2号位置,5号位置,我们可以怎么找呢,(1号 与 5号两个一凑我们就发现2号位置到5号位置所有元素的和是符合条件的,同理1,号和2号,我们找到2号位置自己,2号位置和5号位置我们找到3号位置到5号位置)

  • 用一个更笨点的话去说,我告诉你现在1和2之间有n个符合条件区间,我现在也知道5号位置与1和2也可以构成一个符合条件的区间,其实就是最新的符合条件的1个加上之前存在的符合条件的个数(不断递加)

  • 我们如何去找到这个递推公式呢,1号和2号产生了1个符合条件的区间,1 ,2 ,5,其实就是1和5组合2和5组合,用每次都加上上一次满足的个数递加

  • 我们使用sum数组记录前缀和取模,res[i]就是取模之后i出现的次数代码一定仔细看

int solution(int sum[],int a[],int res[]){
   long long ans = 0;
   forint i = 0 ; i <= n ; i++){
   	cin>>a[i];
   	sum[i] = (sum[i - 1] + a[i])%k;//前缀和的取模
   	ans += res[sum[i]];
   	res[sum[i]]++;
   }
   return ans - res[0] ;//res[0]肯定是符合条件的只要是取模为0都说明可以被k整除
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dou_Huanmin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值