• Codeforces 1333C Eugene and an array


    Description

    一个数列中若有一个子段的和为 $0$,则这个数列是「不好的」,给定一个数列求这个数列内有多少个「好」的子段。

    Solution

    我们记 $f_i$ 表示 以 $i$ 结尾的合法段的个数,显然,这题就是要我们求 $sum_{i=1}^{n} f_i$。

    我们考虑依次求出每一个 $f_i$。设想,我们这次要求的段的右端点显然都是 $i$,左端点可以是 $[1, i]$ 中的每一个值。那么哪些左端点是合法的呢?显然这是一个后缀,也就是说,如果左端点是 $p$ 的时候已经不合法了,那么左端点是 $q$($q<p$)的时候显然是不合法的,因为后者包含了 前者所包含的全部子段

    那么我们只要求出最小的合法的位置 $p$,就知道 $f_i = i - p + 1$ 了(即 $[p, i]$ 中的位置的个数)。我们知道 $i$ 以前可能会有若干个和为 $0$ 的段,那么,$p$ 就是这些段的 左端点的最大值 $ extbf{+1}$,因为当 $p$ 小于等于这个左端点的最大值时,这个含有最大左端点的 $0$ 段就一定被完整包含了。

    所以我们可以每次计算完 $i$ 的贡献后更新这个左端点的最大值。显然只要计算一遍前缀和(仍然存在 $a$ 中),那么如果有一个位置 $j$($j < i$)满足 $a_j = a_i$,那么 $[j+1,i]$ 就是一个 $0$ 段。这里我们可以用 map 来存储一下上一次出现某个数的位置,记作 $lastpos_{a_i}$,那么 $[lastpos_{a_i} + 1, i]$ 就是一个 $0$ 段,左端点为 $lastpos_{a_i} + 1$。那么第 $i$ 个数考虑过后的 $p$,就是 $max{ ext{old } p, (lastpos_{a_i}+1)+1}$。

    程序里面为了方便,存储的 maxl 其实就是 $p - 1$,那么更新答案应该改为 $i - (p - 1) = i - maxl$。

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    int n, a[200005], ans;
    map<int, int> lastpos;
    signed main()
    {
    	lastpos[0] = 0;
    	cin >> n;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> a[i];
    		a[i] += a[i - 1];
    	}
    	for(int i = 1, maxl = 0; i <= n; i++)
    	{
    		if(lastpos.count(a[i])) maxl = max(maxl, lastpos[a[i]] + 1);
    		ans += i - maxl;
    		lastpos[a[i]] = i;
    	}
    	cout << ans << endl;
    	return 0;
    }
  • 相关阅读:
    Linux下编辑、编译、调试命令总结——gcc和gdb描述
    scanf函数读取缓冲区数据的问题
    Windows下设置Ubuntu引导项
    前端术语汇总笔记(会保持更新)
    实现动态加载一个 JavaScript 资源
    提取一个字符串中的数字,并将其转为数组
    CSS3图片倒影技术
    js函数聚合
    js继承函数封装
    联动菜单实现思路
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1333C.html
Copyright © 2020-2023  润新知