This commit is contained in:
Zengtudor 2025-07-31 10:46:15 +08:00
parent 5505498421
commit 3aafc65dc3
11 changed files with 778 additions and 0 deletions

55
src/7/31/U130826.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using ll = int64_t;
void ptv(std::vector<ll>&v){
std::cout<<"[";
for(ll i=1;i<v.size();i++){
std::cout<<v[i]<<" ,";
}
std::cout<<"]\n";
}
void solve(){
static std::string s;
std::cin>>s;
s=' '+s;
ll lok=-1;
static std::vector<ll> lv;
lv.clear();
lv.resize(s.size(),0);
static std::deque<ll> q;
q.clear();
for(ll i=1;i<s.size();i++){
if(s[i]=='('){
q.push_back(i);
}else if(s[i]==')'){
if(q.size()!=0){
lv[i]=q.back();
if(lok!=-1){
if(q.size()==1){
lv[i]=lok;
}
}else{
lok=q.back();
}
q.pop_back();
}else{
lok=-1;
}
}
}
ptv(lv);
}
int main(){
ll t;
std::cin>>t;
while(t--){
solve();
}
}

199
src/7/31/U130826.md Normal file
View File

@ -0,0 +1,199 @@
为了解决这个问题我们需要统计给定字符串中所有合法的子串数量。合法子串需要满足三个条件长度至少为3子串内部不包括边界恰好有一个'*',并且去掉这个'*'后,剩余字符串是一个括号匹配串。
### 方法思路
1. **预处理每个位置的左右'*'位置**:对于每个位置,我们预处理其左边最近和右边最近的'*'的位置。这有助于在枚举中心点(即'*')时,快速确定其左右边界,确保子串内部只有一个'*'。
2. **枚举中心点**:遍历字符串中的每个'*',将其作为子串内部的唯一'*'。
3. **处理左边部分**:对于每个中心点,从中心点左侧开始向左扫描到左边界。在扫描过程中,维护当前子串的平衡值(即括号匹配情况)和最小前缀和(确保过程中没有不匹配的括号)。如果遇到左括号'('且最小前缀和非负,则记录当前平衡值。
4. **处理右边部分**:从中心点右侧开始向右扫描到右边界。同样维护平衡值和最小前缀和。如果遇到右括号')'且最小前缀和等于当前平衡值(即最小前缀和出现在序列末尾),则记录当前平衡值。
5. **统计匹配**对于左边部分记录的每个平衡值x在右边部分查找平衡值为-x的记录并累加匹配数量。
### 解决代码
```cpp
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
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> left_star(n, -1);
vector<int> right_star(n, n);
int last = -1;
for (int i = 0; i < n; i++) {
left_star[i] = last;
if (s[i] == '*') {
last = i;
}
}
last = n;
for (int i = n-1; i >= 0; i--) {
right_star[i] = last;
if (s[i] == '*') {
last = i;
}
}
long long ans = 0;
for (int pos = 0; pos < n; pos++) {
if (s[pos] != '*') continue;
int left_bound = (left_star[pos] == -1) ? 0 : left_star[pos] + 1;
int right_bound = (right_star[pos] == n) ? n-1 : right_star[pos] - 1;
map<int, int> left_map;
int cur_left = 0, min_cur_left = 0;
for (int i = pos-1; i >= left_bound; i--) {
int val = (s[i] == '(') ? 1 : -1;
int new_cur = val + cur_left;
int new_min = min(val, val + min_cur_left);
cur_left = new_cur;
min_cur_left = new_min;
if (s[i] == '(' && min_cur_left >= 0) {
left_map[cur_left]++;
}
}
map<int, int> cnt_r;
int cur_r = 0;
int min_cur_r = 0;
for (int j = pos+1; j <= right_bound; j++) {
int val = (s[j] == '(') ? 1 : -1;
cur_r += val;
min_cur_r = min(min_cur_r, cur_r);
if (s[j] == ')' && min_cur_r == cur_r) {
cnt_r[cur_r]++;
}
}
for (const auto& p : left_map) {
int x = p.first;
auto it = cnt_r.find(-x);
if (it != cnt_r.end()) {
ans += p.second * it->second;
}
}
}
cout << ans << '\n';
}
return 0;
}
```
### 代码解释
1. **预处理左右'*'位置**:使用两个数组`left_star`和`right_star`,分别存储每个位置左侧和右侧最近'*'的位置。这有助于在枚举中心点时快速确定左右边界。
2. **枚举中心点**:遍历字符串中的每个'*',将其作为可能的子串内部唯一'*'。
3. **处理左边部分**:从中心点左侧开始向左扫描,维护当前子串的平衡值和最小前缀和。如果遇到左括号'('且最小前缀和非负,则记录当前平衡值。
4. **处理右边部分**:从中心点右侧开始向右扫描,同样维护平衡值和最小前缀和。如果遇到右括号')'且最小前缀和等于当前平衡值,则记录当前平衡值。
5. **统计匹配**:对于左边部分记录的每个平衡值`x`,在右边部分查找平衡值为`-x`的记录。每匹配一次,就累加一次组合数量,最终得到合法子串的总数。
这种方法高效地利用了预处理和动态维护平衡值确保在O(n log n)时间内解决问题,满足题目要求。
### 平衡值和最小前缀和详解
在解决括号匹配问题时,平衡值和最小前缀和是两个关键概念,用于高效地判断括号序列的合法性。下面我将详细解释这两个概念及其在算法中的应用:
#### 1. **平衡值 (Balance Value)**
- **定义**:平衡值表示当前括号序列中左括号与右括号的数量差。具体计算规则:
- 遇到左括号 `(`:平衡值 +1
- 遇到右括号 `)`:平衡值 -1
- **意义**
- 平衡值为正:左括号多于右括号
- 平衡值为零:左右括号完全匹配
- 平衡值为负:右括号多于左括号(非法状态)
- **示例**
- 序列 `(()`:平衡值变化 `0 → 1 → 2 → 1`
- 序列 `())`:平衡值变化 `0 → 1 → 0 → -1`(非法)
#### 2. **最小前缀和 (Minimum Prefix Sum)**
- **定义**:在遍历过程中,记录从起始位置到当前位置的所有平衡值的最小值。
- **意义**
- 检测序列是否在任何时刻出现非法状态(平衡值<0
- 保证整个子串的括号匹配有效性
- **关键性质**
- 最小前缀和 ≥ 0序列始终合法无右括号多余的情况
- 最小前缀和 < 0序列存在非法位置
### 在算法中的应用
#### 左边部分扫描(向左遍历)
```cpp
for (int i = pos-1; i >= left_bound; i--) {
int val = (s[i] == '(') ? 1 : -1;
cur_left = val + cur_left; // 更新平衡值
min_cur_left = min(val, val + min_cur_left); // 更新最小前缀和
if (s[i] == '(' && min_cur_left >= 0) {
left_map[cur_left]++; // 记录有效左边界
}
}
```
- **操作逻辑**
1. 从星号左侧开始向左扫描
2. 遇到左括号才记录(因为合法子串必须以 `(` 开头)
3. 仅当 `最小前缀和 ≥ 0` 时记录平衡值(保证子串有效性)
#### 右边部分扫描(向右遍历)
```cpp
for (int j = pos+1; j <= right_bound; j++) {
int val = (s[j] == '(') ? 1 : -1;
cur_r += val;
min_cur_r = min(min_cur_r, cur_r);
if (s[j] == ')' && min_cur_r == cur_r) {
cnt_r[cur_r]++; // 记录有效右边界
}
}
```
- **操作逻辑**
1. 从星号右侧开始向右扫描
2. 遇到右括号才记录(因为合法子串必须以 `)` 结尾)
3. 仅当 `最小前缀和 == 当前平衡值` 时记录:
- 表明从开始到当前位置未出现非法状态
- 且当前平衡值是最小值(无未匹配的右括号)
### 匹配原理
- **核心条件**:整个子串(去掉星号)需满足:
```
左边平衡值 + 右边平衡值 = 0
```
- **匹配操作**
```cpp
for (const auto& p : left_map) {
int x = p.first;
if (cnt_r.count(-x)) {
ans += p.second * cnt_r[-x];
}
}
```
- **示例**
- 左边记录平衡值 `x = 1`左括号多1个
- 右边需匹配平衡值 `y = -1`右括号多1个
- `x + y = 0` → 构成完整匹配
### 算法特点
1. **高效性**
- 每个字符最多被扫描两次(左/右各一次)
- 哈希表操作均摊时间复杂度 O(1)
- 总时间复杂度 O(n),满足 ∑|s| ≤ 10⁶ 的要求
2. **正确性保障**
- 预处理星号边界确保唯一性
- 平衡值检测保证括号匹配
- 最小前缀和检测排除非法子串
3. **边界处理**
- 星号不在子串边界(预处理保证)
- 子串长度 ≥3扫描范围控制
通过平衡值和最小前缀和的协同作用,算法高效地筛选出所有满足条件的合法子串,完美解决了括号匹配与星号位置约束的双重挑战。

80
src/7/31/U130826d.cpp Normal file
View File

@ -0,0 +1,80 @@
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
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> ls(n, -1);
vector<int> rs(n, n);
int last = -1;
for (int i = 0; i < n; i++) {
ls[i] = last;
if (s[i] == '*') {
last = i;
}
}
last = n;
for (int i = n-1; i >= 0; i--) {
rs[i] = last;
if (s[i] == '*') {
last = i;
}
}
long long ans = 0;
for (int pos = 0; pos < n; pos++) {
if (s[pos] != '*') continue;
int lb = (ls[pos] == -1) ? 0 : ls[pos] + 1;
int rb = (rs[pos] == n) ? n-1 : rs[pos] - 1;
map<int, int> lm;
int cl = 0, mincl = 0;
for (int i = pos-1; i >= lb; i--) {
int val = (s[i] == '(') ? 1 : -1;
int nc = val + cl;
int nmin = min(val, val + mincl);
cl = nc;
mincl = nmin;
if (s[i] == '(' && mincl >= 0) {
lm[cl]++;
}
}
map<int, int> cntr;
int cr = 0;
int mincr = 0;
for (int j = pos+1; j <= rb; j++) {
int val = (s[j] == '(') ? 1 : -1;
cr += val;
mincr = min(mincr, cr);
if (s[j] == ')' && mincr == cr) {
cntr[cr]++;
}
}
for (const auto& p : lm) {
int x = p.first;
auto it = cntr.find(-x);
if (it != cntr.end()) {
ans += p.second * it->second;
}
}
}
cout << ans << '\n';
}
}

10
src/7/31/match1.ans Normal file
View File

@ -0,0 +1,10 @@
23
144
24
5
3
1
24
24
24
3

11
src/7/31/match1.in Normal file
View File

@ -0,0 +1,11 @@
10
(((((((((((((((((((((((*)))))))))))))))))))))))))
()()()()()()()()()()()()*()()()()()()()()()()()()(
((((((((((((((((((((((((*)))))))))))))))))))))))))
*((*)()*(*)*))*)**((*()((**)((*)(()*()(**)(()(*(*(
******(*(*((*()((*)*)(((*((**(*((*)*(*)((()**(***
(*()((*(*(((()((*(**()**))(**(*)(**))()((*****)((
((((((((((((((((((((((((*)))))))))))))))))))))))))
((((((((((((((((((((((((*)))))))))))))))))))))))))
((((((((((((((((((((((((*)))))))))))))))))))))))))
*(*(()*()(*)*)****())((*(*(((())(**)(((****)*((***

10
src/7/31/match3.ans Normal file
View File

@ -0,0 +1,10 @@
224
12544
223
29
224
34
25
12544
224
223

11
src/7/31/match3.in Normal file
View File

@ -0,0 +1,11 @@
10
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((*)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()*()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()(
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((*)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
()(*(**)*()*(*)(*)()(**)***)***(**(*)*)*()*(*)*)()(((*(())(((*()(***(*()*))*))()*(((*)())***(((**()(**(*()(())*))(***)(*)))()**())*(((**(**)*(*)**))*(*(*(**((*)(()*)***(((*))(*(******(**(*)(*)((((****(**))*(**((()(*)*()(*)()*(*(*))(((((**(((()*()(***)***)*******(**()((()*(*()(((*(****(**()()*(*(**(*()**)*(**(()*)**)()()***)**)*())**)()*(**(((**)*(*(()((*()((**((***()*((()((*)****)()((((()*)*(**(*(*)*****()))***)(((**(*((*******()()))*(()*)**(((((
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((*)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
*(*(*(*)())*(())(***)(((*(()()()(*(**(*(*(***()()()()(*))(*)()()))**(*(()***)(**(((*(((**((***()*****((*())*(*(*(*(((((**(()(((()((**(((*()*((*(()((*)(*)(****)(()(**(*(()*)(((((**(((*****)))*)*)**)()*)*()*)**(*(**(*((***(()**(*)*()()(*))(****))*())****)(((((***)(*)()****(**)**(**)**(**)((()*((*(()))(()((*((()*())*((*)((*)*)**)*(**(*(*))******(()((*(())(((*(**()(*)((*)***)()***()(****)**(*)(*()(**)**)*****)(*((*)(((*))*(**(*)*(()(((***))(***(**())
(**(*(((()*))**(**(*(*()(*(*(()*())()*(*)*)*)(*()*(*((****)(**(*((***))((()()*)()(**()())(((*)(**))(****(((***()*((*)*(*(((**()((*(()*())*)()(*)(**)(*(((****(*()*(**)((((*(***((**((*)(*()(()*(((**)))****((((*()*()))((())())**(*(*())(**)())((((**()(**)**(**()********)()*))**(((**(*(**(**)*(*(*)**))(*)*)))(*(*(*)*(**(*(*)*)*()(**())**)*)*())*)*()(****((*(())()(**(*((***(**())(()(()))**))(((*)*(*((()(**()(((*()()**(*)***(*()(((*)()***())(()(*((**()*
()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()*()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()(
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((*)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((*)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

100
src/7/31/match5.ans Normal file
View File

@ -0,0 +1,100 @@
6247500
4998
4998
6247500
6247500
4998
6247500
4998
4999
4999
4999
6250000
4998
4999
6247500
6247500
6247500
6247500
4998
4999
6250000
4998
6250000
4999
4999
6250000
4998
4998
4998
6250000
6250000
4998
6247500
6250000
4998
4998
6247500
4998
4998
6250000
4998
6250000
4998
4999
4998
4999
4999
4999
4998
6247500
6250000
4999
6250000
4999
6247500
4998
4998
6247500
4999
6250000
6247500
4999
4999
6250000
4999
6250000
6250000
6250000
6250000
6247500
6250000
4998
4999
4998
4998
4998
4999
4999
4998
4998
6247500
4998
6247500
6247500
6250000
4999
4998
4998
4999
6247500
4998
4998
6247500
6247500
4998
6250000
4998
4998
4999
6247500

101
src/7/31/match5.in Normal file

File diff suppressed because one or more lines are too long

100
src/7/31/match7.ans Normal file
View File

@ -0,0 +1,100 @@
4555677
571
2322500
400
568
583
1865
247401
165
691
265000
3903
702500
1594
384
514
544
999
1520000
1627500
556
540
857157
204
577
621
242403
444822
1314474
194922
3462500
135
565
491
807177
779
41
539
4830567
541
549
624
624
353
4275000
516
575
538
264
545
562
602259
1308
556
624
1376949
608
555
1945
550
746
429
468
578
1339
1767
418
1460
504798
1707500
567
567
609
3735000
1048
760000
571
615
1531887
1142
113
583
1876
2976309
530
574
574
559
1629
391
565
565
205
591
1225
582
15
1055
162500
542500

101
src/7/31/match7.in Normal file

File diff suppressed because one or more lines are too long