Codeforces 519D A and B and Interesting Substrings (前綴和)

這次的codeforces真是無與倫比的水,但是即使如此,這道幾百個人做出來的D我依然沒有過,實在是sad story。

具體來說題目的話,題目是說給定每個字母的權值(一共只有26個小寫英文字母的組合單詞),以及一個字符串,找出這個字符串的子字符串中的滿足

1. 除去第一個和最後一個字母中間加和爲0的。

2. 第一個字母和最後一個字母相同的。

輸出這樣的字符串有幾個。

剛開始我竟然想用線段樹+RMQ的思想去做,真是罪過罪過,主要是當時看到區間的東西就一下子想到線段樹了臥槽。

後來比賽中被一位好友說了一句可以用前綴和做,我靈光一閃,寫出了一個O(n^2)的答案,媽蛋這不是跟暴力枚舉一樣的複雜度嘛。後來比賽結束看題解的時候才發現了問題所在。我的做法是檢測當前前綴和,如果這個前綴和的數值以前出現過,那麼就依次比較這些前綴和的對應字母和自己的對應字母是不是相等,於是這樣就導致了O(n^2)的TLE。

後來看到了題解的思想是這樣的。掃一遍的過程中,檢測當前字母,記錄字母所對應的前綴和,記錄該前綴和之前出現的次數。舉個例子比較好說,比如說現在掃到字母a對應的前綴和爲36,並且36之前出現過1次(這一次也是字母a的,因爲我們先枚舉的是字母),那麼這個時候明顯的,滿足條件的sub string多了一個。如果36出現了兩次呢?那思考一下容易得出,sub string應該這時候是加了兩個的,這個也就是處理的精妙之處所在。

所以總的來說,數據結構就該是一個map數組,把每一個前綴和對應的次數存在map裏面,然後每一個字母對應一個map。

#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <functional>
#include <map>
#include <string.h>
#include <iomanip>
#include <utility>
#define INF 0x3fffffff
using namespace std;
int n, m, k, t, p, q, x, y;
string s;
int w[30];
long long sum[100005];
map<long long, int> mymap[30];
int main() {
	for (int i = 0; i < 26; i++) {
		cin >> w[i];
	}
	long long res = 0;
	cin >> s;
	for (int i = 0; i < s.size(); i++) {
		sum[i] = sum[i - 1] + w[s[i] - 'a'];
	}

	for (int i = 0; i < s.size(); i++) {
		int index = s[i] - 'a';
		if (i == 0) {
			mymap[index][sum[i]]++;
			continue;
		}
		if (mymap[index].count(sum[i - 1])) {
			res += mymap[index][sum[i - 1]];
		}
		mymap[index][sum[i]]++;
	}
	cout << res << endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章