当然可以!让我们逐步分析这个代码,特别是对 total_cost
的操作。
代码结构解析
- 输入部分: “`cpp int test_cases; cin >> test_cases; // 输入测试用例的数量
while (test_cases–) {
int length;
cin >> length; // 输入字符串的长度
string str;
cin >> str; // 输入字符串
在这里,我们首先读取测试用例的数量,然后在每个测试用例中,读取字符串的长度和内容。
2. **初始化变量**:
```cpp
vector<int> prefix_sum(length + 1, 0);
unordered_map<int, int> freq_map; // 用哈希表代替Counter
long long total_cost = 0;
prefix_sum
:用于存储前缀和,大小为length + 1
,初始值均为0。freq_map
:用于统计每一个前缀和出现的频率。total_cost
:用于累积总成本,初始为0。
更新前缀和与频率映射:
for (int i = 1; i <= length; i++) {
// 更新哈希表
freq_map[prefix_sum[i - 1]]++;
// 更新前缀和
prefix_sum[i] = prefix_sum[i - 1] + (str[i - 1] == '1' ? 1 : -1);
// 更新总成本
total_cost -= i;
total_cost += freq_map[prefix_sum[i]];
}
对于 total_cost
的详细解释:
更新哈希表: 每次循环开始时,我们将前一个位置的前缀和(即
prefix_sum[i-1]
)加入到频率映射中。这样做是为了记录在当前索引之前相同前缀和出现了多少次。计算当前前缀和: 前缀和由前一个元素的值加上当前字符决定。如果字符是
'1'
则加一,如果是'0'
则减一。更新总成本 (
total_cost
):首先,我们通过
total_cost -= i;
减去当前索引i
。这一行通常意味着对于每一个位置,我们认为其对总成本产生了一定程度的负影响或者说其位置本身是一种消耗。然后,使用
total_cost += freq_map[prefix_sum[i]];
将该位置对应前缀和在频率映射中的次数加回到总成本。这表示如果有多个相同的前缀和出现在之前的位置,这些相同值之间形成了一种组合,而这些组合对成本有积极影响。也就是说,如果某个子串以某个点结束且其余部分都是零,可以减少一些“负担”,因此它们需要被计入总费用中。
后续处理
- 排序与计算额外成本:
sort(prefix_sum.begin(), prefix_sum.end());
long long count = 0;
long long prev_sum = 0;
for (int i = 0; i < prefix_sum.size(); i++) {
prev_sum += prefix_sum[i];
count += 1;
total_cost += prefix_sum[i] * count - prev_sum;
}
在这段代码中,对所有的前缀和进行排序,并计算额外的成本。在这个过程中,
每一次遍历我们都会增加计数器(代表了当前已经考虑了多少项),并同时维护一个累积量(即
prev_sum
)。最终计算出来的是按顺序考虑过后,对于已有项的新项所造成的整体“负担”或代价变化。
- 输出结果:
cout << total_cost << endl;
最后输出经过以上所有操作后的总费用或代价,即为答案。
总结
这个代码实现主要使用了哈希表来记录每个状态出现的次数,以及利用数组来优化权重计算过程,从而有效地解决问题。在复杂度上,它比简单暴力的方法更高效,因为避免了多次重复计算相同子串的信息。
内容由零声教学AI助手提供,问题来源于学员提问