#P3575. 第3题-子序列权值
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 18
            Accepted: 5
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年9月5日-菜鸟
                              
                      
          
 
- 
                        算法标签>前缀和          
 
第3题-子序列权值
思路
- 对于任意合法的 i<j<k,有
 
- 
因此每个 “red” 子序列只和其首尾位置相关:权值为 2(k−i)。
 - 
令在位置 j 取字母 e。设
- RL(j):所有在 j 左侧的 r 的位置集合;
 - DR(j):所有在 j 右侧的 d 的位置集合。
 
 - 
则以该 j 为中间字母的总贡献为:
 

- 
只需维护:
- 前缀:到每个位置为止的 r 的个数与下标和;
 - 后缀:从每个位置之后的 d 的个数与下标和。
 
 - 
枚举所有为 e 的位置 j,用上式累加。时间复杂度 O(n),空间复杂度 O(n)。使用 64 位整型保存答案。
 
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int n;
	string s;
	if (!(cin >> n)) return 0;
	cin >> s; // 字符串只含 r/e/d
	// 采用 1-based 下标进行计算,便于套用公式
	vector<long long> preRcnt(n + 1, 0), preRsum(n + 1, 0);
	for (int i = 1; i <= n; ++i) {
		preRcnt[i] = preRcnt[i - 1] + (s[i - 1] == 'r');
		preRsum[i] = preRsum[i - 1] + ((s[i - 1] == 'r') ? i : 0);
	}
	vector<long long> sufDcnt(n + 2, 0), sufDsum(n + 2, 0);
	for (int i = n; i >= 1; --i) {
		sufDcnt[i] = sufDcnt[i + 1] + (s[i - 1] == 'd');
		sufDsum[i] = sufDsum[i + 1] + ((s[i - 1] == 'd') ? i : 0);
	}
	long long ans = 0;
	for (int j = 1; j <= n; ++j) {
		if (s[j - 1] == 'e') {
			// 按推导公式累加贡献:2 * ( |R_L| * sum(D_R) - |D_R| * sum(R_L) )
			ans += 2LL * (preRcnt[j] * sufDsum[j] - sufDcnt[j] * preRsum[j]);
		}
	}
	cout << ans << "\n";
	return 0;
}
Python
import sys
data = sys.stdin.read().strip().split()
if not data:
    sys.exit(0)
n = int(data[0])
s = data[1].strip()
# 使用 1-based 下标便于直接套用公式
preRcnt = [0] * (n + 1)
preRsum = [0] * (n + 1)
for i in range(1, n + 1):
    preRcnt[i] = preRcnt[i - 1] + (1 if s[i - 1] == 'r' else 0)
    preRsum[i] = preRsum[i - 1] + (i if s[i - 1] == 'r' else 0)
sufDcnt = [0] * (n + 2)
sufDsum = [0] * (n + 2)
for i in range(n, 0, -1):
    sufDcnt[i] = sufDcnt[i + 1] + (1 if s[i - 1] == 'd' else 0)
    sufDsum[i] = sufDsum[i + 1] + (i if s[i - 1] == 'd' else 0)
ans = 0
for j in range(1, n + 1):
    if s[j - 1] == 'e':
        # 2 * ( |R_L| * sum(D_R) - |D_R| * sum(R_L) )
        ans += 2 * (preRcnt[j] * sufDsum[j] - sufDcnt[j] * preRsum[j])
print(ans)
Java
import java.io.*;
import java.util.*;
public class Main {
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line1 = br.readLine();
		if (line1 == null || line1.trim().isEmpty()) return;
		int n = Integer.parseInt(line1.trim());
		String s = br.readLine().trim(); // 字符串只含 r/e/d
		// 使用 1-based 下标
		long[] preRcnt = new long[n + 1];
		long[] preRsum = new long[n + 1];
		for (int i = 1; i <= n; i++) {
			preRcnt[i] = preRcnt[i - 1] + (s.charAt(i - 1) == 'r' ? 1 : 0);
			preRsum[i] = preRsum[i - 1] + (s.charAt(i - 1) == 'r' ? i : 0);
		}
		long[] sufDcnt = new long[n + 2];
		long[] sufDsum = new long[n + 2];
		for (int i = n; i >= 1; i--) {
			sufDcnt[i] = sufDcnt[i + 1] + (s.charAt(i - 1) == 'd' ? 1 : 0);
			sufDsum[i] = sufDsum[i + 1] + (s.charAt(i - 1) == 'd' ? i : 0);
		}
		long ans = 0;
		for (int j = 1; j <= n; j++) {
			if (s.charAt(j - 1) == 'e') {
				// 2 * ( |R_L| * sum(D_R) - |D_R| * sum(R_L) )
				ans += 2L * (preRcnt[j] * sufDsum[j] - sufDcnt[j] * preRsum[j]);
			}
		}
		System.out.println(ans);
	}
}
        题目内容
小红有一个长度为 n 的字符串 s=s1,s2,…,sn,她定义长度为 3 的子序列 sisjsk 的权值为 ∣i−j∣+∣i−k∣+∣j−k∣ 。
现在,小红希望你计算所有 “red” 子序列的权值之和。
如果字符串 t=“red” 可以通过删除字符串 s 中的若干(可能为零或全部)元素得到,则字符串 t 是字符串 s 的 “red” 子序列。
输入描述
第一行输入一个整数 n(1≤n≤2×105) ,表示字符串的长度。
第二行输入一个长度为 n ,且只由 ′r′、′e′、′d′ 三个小写字母
输出描述
在一行上输出一个整数,代表所有 “red” 子序列的权值之和。
样例1
输入
4
reed
输出
12
说明
在该样例中,一共有两个不同的 “red” 子序列:
删除第二个字符得到的子序列 s1s3s4 权值为 ∣1−3∣+∣1−4∣+∣3−4∣=6;
删除第三个字符得到的子序列 s1s2s4 权值为 ∣1−2∣+∣1−4∣+∣2−4∣=6 。
样例2
输入
7
redeeed
输出
52