子串權值和


傳送門

題目描述

咕咕有一個長度為 \(n\) 的只包含小寫字母的字符串,對於該字符串的任意一個子串,其權值定義為該子串中包含的字符種數。

你能告訴咕咕,該字符串的所有子串的權值之和是多少嗎?

INPUT

輸入包含多組數據,第一行一個整數 \(t\),表示輸入數據的組數。

每組數據共 \(1\) 行,第一行一個字符串 \(s\),長度為 \(n\)

OUTPUT

對於每組數據,輸出一行一個整數,表示該字

符串的所有子串的權值之和。

Sample Input:

2
gugugu
ggguuu

Sample Output:

36
30

數據范圍

\(1 \le t \le 20, 1 \le n \le 10^5\)

思路

注意到字符的種類只有 \(26\) 個,因此我們可以單獨算出每個字符的貢獻

可以發現每個字符在任意一個子串中的貢獻只有兩種 \(1 or 0\),因此我們倒着算比較容易計算

對於一個字符 \(c\), 只有在一段連續的不包含 \(c\) 的字符串中才不會計算貢獻,並且字符串個數是 \(n \times (n + 1) / 2\)

CODE
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int T; cin >> T;
  while(T -- ) { 
    string s; cin >> s;
    int n = s.size();
    vector<int> a(n);
    for(int i = 0; i < n; i ++ ) {
      a[i] = (s[i] - 'a');
    } 

    long long ans = 0;

    for(int k = 0; k < 26; k ++ ) {
      for(int i = 0; i < n; i ++ ) {
        while(i < n && a[i] == k) i ++;
        int j = i;
        while(j < n - 1 && a[j + 1] != k) j ++;
        long long len = j - i + 1;
        ans += len * (len + 1) / 2;
        i = j;
      }
    } 
    ans = 1LL * n * (n + 1) * 13 - ans;
    cout << ans + 1 << "\n";
  }
  return 0;
}


免責聲明!

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



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