zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView
    Maven 本地打war包
    数据库性能优化一
    SessionStateMode之Redis共享session
    SessionStateMode之SQL Server共享session
    iframe跨域
    Jenkins发布MVC应用程序
    Docker入门之一Docker在Window下安装
    Window下SVN服务器搭建以及客户端使用
    Window下Jenkins的安装
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1333C.html
Copyright © 2011-2022 走看看