C. Eugene and an array (詳細講解)


C. Eugene and an array

  • 看我博客我有沒看懂的地方,或者其他疑問,可以加我qq和我交流~我會及時解答
  • qq:1244536605 (加好友時備註一下 博客 )

標籤

  • 難想的暴力。

簡明題意

  • D題沒啥思路,放棄比賽直接開始寫博客哈哈哈哈~
  • 給定n長的數組a[]
  • (接下來的文章中,我把連續子序列稱爲子串,大家注意一下哈)
  • 題目定義了一個數組什麼時候是good的。題目是這樣定義的:一個數組b[],如果它是由a[]數組刪掉頭部幾個元素,再從尾部刪掉幾個元素得到的,且b[]數組不包含一個和爲0的子串,那麼b[]是good的。
  • 題目定義得很繞。。什麼頭部刪幾個,尾部刪幾個,,這都是誤導的信息。實際上就是說,如果一個數組是good的,那麼這個數組需要是a[]的一個子串,且這個數組本身不包含和爲0的子串。題目中,頭部刪幾個,尾部刪幾個,我開始還想了半天這是啥…後來才明白其實就是告訴你它是a[]的一個子串。
  • 現在要求a[]有多少個子串是good的。

思路

  • 包含a[i]的子串一共有多少個?
  • 顯然是n個。從a[i]往左邊延伸得到i-1個,從a[i]往右延伸是n-i個,加上自己,就是n個。
  • 那麼我們可以枚舉每一個a[i],求a[i]往左邊可以延伸出多少個good的子串,再把對於每個a[i]求得的值加起來即可。
  • 下面畫一個圖,藍色部分表示我們正在考慮的a[i]。假設紅色和棕色標出的區間和爲0.相當於現在我們固定了子串的右端點,想要求出有多少個左端點可選,使得這個子串good。
    在這裏插入圖片描述
  • 那麼很顯然,左端點不可能在L3L_3的前面。那麼是不是相當於我們在枚舉a[i]的時候要維護,和爲0的區間的最大左端點?是的。
  • 假設我們維護的這個最大左端點是max_l,那麼對於每一個a[i],我們讓ans += i-max_l就好了。
  • 嗯…我好像講完了,就是這麼簡單,維護就好了。

---------------------------------------分割線-----------------------------------

  • 可能難點在於怎麼維護。我說說我的思路。我一看到區間和爲0,我想到了前綴和,區間[i,j][i,j]和爲0等價於sum[i1]=sum[j]sum[i-1]=sum[j]。那麼我們可以先前綴和一下,然後考慮每一個a[i]的時候,直接找距離i最近的j且sum[j]=sum[i]。就能找到這個和爲0的區間了,然後用這個更新max_l,再用max_l更新答案即可。

注意事項


總結


AC代碼

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring> 
#include<stack>
#include<map>
#include<queue>
#include<cstdio>	
#include<set>
#include<map>
#include<string>
using namespace std;

const int maxn = 2e5 + 10;

long long dp[maxn];

map<long long, int> rec;//維護每個前綴和最近一次出現的位置
void solve()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> dp[i], dp[i] += dp[i - 1];
		rec[dp[i]] = -1;
	}

	long long ans = 0;
	int max_l = -1;
	rec[0] = 0;
	for (int i = 1; i <= n; i++)
	{
		if (rec[dp[i]] != -1) 
			max_l = max(max_l, rec[dp[i]]);
		rec[dp[i]] = i;
		ans += i - (max_l + 1);//max_l表示前綴和相等的下標,而max_l+1纔是實際的區間
	}
	
	cout << ans;
}

int main()
{
	//freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章