题目链接:https://agc023.contest.atcoder.jp/tasks/agc023_a
题意:在一串数字中找出连续数字和等于0的个数。
范围:
1≤N≤2e5
−1e9≤A[i]≤1e9
思路:最开始直接上线段树,果不其然TLE, 然后换前缀和(暴力枚举区间),也TLE了,原谅孤陋寡闻的我不知道尺取法(应该是这个思想),换了之后就AC了(35ms)
总而言之就是:前缀和 + 尺取法
以下是暴力代码:
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const int maxn = 2e5+1;
LL qzh[maxn];
int N;
int main() {
scanf("%d",&N);
LL ans = 0;
qzh[0] = 0;
int x;
for(int i = 1; i <= N; i++) {
scanf("%d",&x);
qzh[i] = qzh[i-1] + x;
}
for(int i = 1; i <= N; i++){ //太暴力了
for(int j = i; j <= N; j++){
if(qzh[j]-qzh[i-1]==0)
ans++;
}
}
printf("%lld\n",ans);
return 0;
}
以下是正解代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn = 2e5+2;
long long num[maxn];
int main(){
int n;
scanf("%d",&n);
memset(num, 0, sizeof(num));
for(int i = 0; i < n; i++){
scanf("%lld",&num[i]);
if(i != 0)
num[i] += num[i-1];//前缀和
}
sort(num,num+n);//从小到大排序,关键之处
long long ans = 0;//最终答案
long long pair = 0;//前缀和相等的对数
if(num[0]==0)//单独考虑,因为下面有i-1
ans++;
for(int i = 1; i < n; i++){
if(num[i] == 0)
ans++;
if(num[i] == num[i - 1])//因为排好序,相等的必然是连续的
pair++;
if(num[i] != num[i - 1] && pair || i == n - 1 && pair){//一旦不相等了,就处理一次
ans += (pair + 1) * pair / 2;//比如说有两对相等的,那么就是num[i-1],num[i],num[i+1],每两个之间的和都为0,就是组合数C(pair+1,2)
pair = 0;//置为0,免得干扰后面的
}
}
printf("%lld\n", ans);
return 0;
}
总结:我太菜啦!