HDU6799 Parentheses Matching(贪心/括号匹配)
Given a string P
consisting of only parentheses and asterisk characters (i.e. "(", ")" and ""), you are asked to replace all the asterisk characters in order to get a balanced parenthesis string with the shortest possible length, where you can replace each "" by one "(", or one ")", or an empty string "".
A parenthesis string S is a string consisting of only parentheses (i.e. "(" and ")"), and is considered balanced if and only if:
● S is an empty string, or there exist two balanced parenthesis strings A
and B such that SS=AB, or there exists a balanced parenthesis string C such that S=(C*)
.
For instance, "", "()", "(())", "()()", "()(())" are balanced parenthesis strings.
Due to some notorious technical inability, if there are several solutions with the shortest possible length, then you have to report the smallest possible one in lexicographical order.
For every two different strings A
and B
of the same length n
, we say A is smaller than B in lexicographical order if and only if there exists some integer kk
such that:
● 1≤k≤n1≤k≤n, and the first (k−1) characters of Aand that of B are exactly the same, and the k-th character of Ais smaller than that of B
.
For instance, "()(())" is smaller than "()()()", and in this case, k=4
.
Input
There are several test cases.
The first line contains an integer T
(1≤T≤), denoting the number of test cases. Then follow all the test cases.
For each test case, the only line contains a string of length n
(1≤n≤), denoting the string P that consists of only parentheses and asterisk characters.
It is guaranteed that the sum of n
in all test cases is no larger than
.
Output
For each test case, output in one line "No solution!" (without quotes) if no solution exists, or otherwise the smallest possible solution in lexicographical order. Note that the output characters are case-sensitive.
Sample Input
5
*))*)
*(*)*
*)*(*
******
((***)()((**
Sample Output
No solution!
()
()()
(())()(())
啊我好菜我好菜我好菜
比赛时队友想出来的思路是首先对原串去括号,最终得到的朴素形式是 **)**)***)*****((*(( ***这样,即左半部分是星号和右括号,右半部分是左括号和星号,否则的话还能继续消括号。然后对于左半部分,尽可能靠左填充左括号(满足字典序最小);右半部分尽可能靠右填充右括号(满足字典序最小)。注意对于))*这样的得判断一下左半部分当前*的数目是否小于当前左括号的数目(可以用前缀和判断),右半部分同理。
证明引用一下题解:
注意到,如果有最短长度的合法解,则不会存在一个被替换为 “(” 的 “*” 在一个被替换为 “)” 的 “*” 右侧。假设存在这样的情况,则交换它们不会使解不合法,但交换后可以发现它们都可以替换为 “”, 这意味着存在更短长度的解,从而导出矛盾。 假设已经得到一个最短长度的合法解,则对于每个被替换为 “)” 的 “*”,如果其右侧存在被替换为 “” 的 “*”,则我们可以交换这两个字符的位置,新解的字典序不会更大,对于 “(” 同理。 因此最短长度的字典序最小合法解一定是替换最左侧的一部分 “*” 为 “(”,最右侧的一部分 “*” 为 “(”,而且它们的数量 cl,cr 满足 cl −cr 是定值,于是我们可以二分查找最小的 cl 使得构造出的串为合 法解。
实际上,我们可以注意到 cl 和 cr 的值是可以直接根据已有括号算出的,因为我们加括号就是为了 抵消对应的括号带来的限制。
垃圾代码仅供提醒我是辣鸡
#include <bits/stdc++.h>
using namespace std;
bool vis[5000005];
char ss[5000005];
int sum_l[5000005], sum_r[5000005];
stack<int> s;//一开始写成stack<char>了 我裂开
stack<char> star;
int main()
{
//freopen("1009.in","r",stdin);
//freopen("my.out","w",stdout);
int t;
cin >> t;
while(t--)
{
scanf("%s",ss);
int len = strlen(ss);
int cnt_l = 0, cnt_r = 0;
while(s.size()) s.pop();
for(int i = 0; i < len; i++)
{
if(ss[i] == '(')
{
s.push(i);
vis[i] = 0;
}
else if(ss[i] == '*')
{
vis[i] = 0;
continue;
}
else if(ss[i] == ')')
{
if(s.size())
{
int left = s.top();
s.pop();
vis[left] = vis[i] = 1;
}
else
{
vis[i] = 0;
continue;
}
}
}
for(int i = 0; i < len; i++)
{
if(!vis[i] && ss[i] == '(') cnt_l++;
if(!vis[i] && ss[i] == ')') cnt_r++;
}
int i;
int ready1 = 0, ready2 = 0;
sum_r[len] = sum_l[len] = 0;
for(int i = 0; i < len; i++)
{
if(i == 0)
{
if(!vis[i] && ss[i] == '(') sum_l[0] = 1;
else sum_l[0] = 0;
continue;
}
sum_l[i] = sum_l[i - 1];
if(!vis[i] && ss[i] == '(') sum_l[i]++;
}
for(int i = len - 1; i >= 0; i--)
{
sum_r[i] = sum_r[i + 1];
if(!vis[i] && ss[i] == ')') sum_r[i]++;
}
bool flag = 1;
while(star.size()) star.pop();
for(i = 0; i < len; i++)
{
if(vis[i]) continue;
if(ss[i] == '(')
{
break;
}
if(ss[i] == ')')
{
if(star.size() < cnt_r - sum_r[i + 1])
{
flag = 0;
break;
}
}
if(ss[i] == '*') star.push('*');
if(ss[i] == '*' && ready1 < cnt_r)
{
ss[i] = '(';
ready1++;
}
}
while(star.size()) star.pop();
// for(i = len - 1; i >= 0; i--)
// {
// if(ss[i]=='*'&&!vis[i])cout<<"lol";
// }
for(i = len - 1; i >= 0; i--)
{
if(vis[i]) continue;
if(ss[i] == ')')
{
break;
}
if(ss[i] == '(')
{
if(star.size() < cnt_l - sum_l[i - 1])
{
flag = 0;
break;
}
}
if(ss[i] == '*') star.push('*');
if(ss[i] == '*' && ready2 < cnt_l)
{
ss[i] = ')';
ready2++;
}
}
//cout<<"ready :"<<ready1<<' '<<ready2<<endl;
//cout<<"cnt:"<<cnt_l<<' '<<cnt_r<<endl;
if(ready1 != cnt_r || ready2 != cnt_l || !flag)
{
cout << "No solution!" << endl;
}
else
{
for(i = 0; i < len; i++)
{
if(ss[i] == '*') continue;;
cout << ss[i];
}
cout << endl;
}
}
return 0;
}
//)**)(()*
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!