子串分值和


【問題描述】

對於一個字符串 S,我們定義 S 的分值 f(S ) 為 S 中出現的不同的字符個 數。例如 f(”aba”) = 2,f(”abc”) = 3, f(”aaa”) = 1。 現在給定一個字符串 S [0..n − 1](長度為 n),請你計算對於所有 S 的非空 子串 S [i.. j](0 ≤ i ≤ j < n),f(S [i.. j]) 的和是多少。

【輸入格式】

輸入一行包含一個由小寫字母組成的字符串 S。

【輸出格式】

輸出一個整數表示答案。

【樣例輸入】

ababc

【樣例輸出】

28

【樣例說明】

子串 f值

a 1

ab 2

aba 2

abab 2

ababc 3

b 1

ba 2

bab 2

babc 3

a 1

ab 2

abc 3

b 1

bc 2

c 1

【評測用例規模與約定】

對於 20% 的評測用例,1 ≤ n ≤ 10;
對於 40% 的評測用例,1 ≤ n ≤ 100;
對於 50% 的評測用例,1 ≤ n ≤ 1000;
對於 60% 的評測用例,1 ≤ n ≤ 10000;
對於所有評測用例,1 ≤ n ≤ 100000。

題解:補一波藍橋杯的題吧,當時O(n^2)寫的,直接暴力沒啥好分享的,有手就行。然后分享一下O(n)的解法,涉及到遞推算之前字符給予的奉獻,因為感覺手寫比較清晰,也方便自己之后的復習,就直接手寫,如下圖(字可能有點辣眼睛):

太難了,要不是有大佬指點,這根本想不到嗷,自己也琢磨挺久的,不過u1s1,這題出的還挺有意思。

代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 7;
int vis[N], next[N];
LL ans = 0, sum = 0, now = 0;
string str;
int main()
{
	ios::sync_with_stdio(false);
	cin >> str;
	memset(vis, -1, sizeof(vis));
	memset(next, 0, sizeof(next));
	for(int i = 0; i < str.length(); i++)
	{
		if(vis[str[i] - 'a'] == -1)
		{
			now++;
			sum += now;
			vis[str[i] - 'a'] = i;
		}
		else
		{ 
			sum += now;
			int lastPos = vis[str[i] - 'a'];
			next[lastPos] = i - vis[str[i] - 'a']; //重復出現的字符離最右邊相同字符的距離 
			vis[str[i] - 'a'] = i;
		} 
	}
//	cout << sum << endl;
	ans += sum;
	int n = str.length();
	for(int i = 1; i < str.length(); i++)
	{
		if(!next[i-1]) //第i-1個字符是唯一的
		{
			sum = sum - (n - (i - 1));
			ans += sum;
		} 
		else
		{
			int dis = next[i-1]; //算出第i-1個字符與它相同的下一個字符的距離 
			sum = sum - dis;
			ans += sum;
		} 
	}
	cout << ans << endl;
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM