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
.
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≤\(10^5\)), 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≤\(10^5\)), 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 \(5\times10^6\)
.
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;
}
//)**)(()*