D. Kousuke‘s Assignment

这题 嗯.......可能我还是刷的太少了——我感觉真的好巧妙啊,我压根都没想到前缀和还有这种作用,果然菜就的多练,一起加油吧 qwq  -^_^- 

        pp废话不多说,我开始讲解思路了:我们看到题目大意其实就是要我们去分割区间,让每一个小区间的和为0,并且使得区间和为零的区间的个数最多。

        了解了题目的大概意思之后,我就想到用前缀和,但我不知道怎么能够一直更新我的指针的位置,就卡住了,下面我讲解一下我看的代码的神之操作:首先你可以运用前缀和数组,其实用一个数也可以,因为我们这次的前缀和用法不同,所以可以直接用sum记录前缀和的值,我们先要了解清楚,我们怎么去划分才能得到更多的区间和为零的区间个数,一定是让区间越小越好,假设数组为:【1,0,-1】,那么当有个数为0时,我们一定是直接把它当作一个区间,而不是去考虑一整个-1,0,1,那么我们要如何去进行这个操作呢,同时又要避免重叠性问题,我们可以直接用一个记录索引的变量index来记录我们前一个美丽子区间的右边界的索引在多少,当我得到0是美丽的子区间的时候,我同时更新index=i,这样能够避免我下一步又会把-1,0,1这个区间算进去。

        下面我讲一下最妙的地方:就是他用了map作为哈希表,当我得到一个新的前缀和的时候,我现在map中判断,有没有出现过,如果出现过,并且它的索引>=我的上一个最美子区间的位置,这就说明我找到了一个新的子区间,cnt++,一旦等于的话,其实是我的特殊情况,就是我在最开始就把0给塞进去,map[0]=-1,我的index也是初始化为-1,这个时候当我第一个数为0,是出现了相等的情况,你们可以好好捋一下,我一开始也是有点不理解,后面就是一整个恍然大悟.

        具体实现代码:

#include <iostream>
#include <cstring>
#include <map>

using namespace std;

const int N = 3e5+10;

long long t,n;
long long a[N];
map<long long,long long> mp; 

int main(void){
	cin>>t;
	long long cnt=0,sum=0;
	long long index=-1;	//记录上一个前缀和为0的区间的边界位置 
	while(t--){
		cin>>n;
		memset(a,0,sizeof(a));
		mp.clear();
		mp[0]=-1; 
		index=-1;
		cnt=0; 
		sum=0;
		for(int i=0;i<n;i++){
			cin>>a[i];
			sum+=a[i];
			if((mp.find(sum)!=mp.end())&&(mp[sum]>=index)){
				cnt++;
				index=i;
			}
			mp[sum]=i;
		}
		cout<<cnt<<endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值