 /**//*
sample:
##-(##+###)
3333333
用下面的數字去填上面的#使得該式子最大 有多個時輸出字典序最小的
首先,去括號
沒有真的去掉,利用括號前的那些正負號來確定每個數字真實的正負號
為每個數字或者括號這樣的整體添加正負號
如下面的例子 +(-(+a+b)+c)
這里在最外的括號及a也要有一個正號

為了轉化出上面的式子用一個棧
1) '(' 如果其前面不是符號,就需要添加一個符號(跟棧頂一樣) push(top)
2) '(' pop
3) '±' push(op^top) 這里把負號當成1
4) '#' 如果其前面不是符號就需要添加一個符號(跟棧頂一樣) push(top)
然后連讀 存起這個數 再pop
正數存在positive 負數存在negative

現在就來貪心 先將digit排序
對于正數,每次將digit里最大的數賦值給positive里長度最大的,或長度相同靠后的
對于負數,每次將digit里最小的數賦值給negative里長度最大的,或長度相同靠前的
可用一個堆來實現,取出后再放進去(這時長度少1了)

*/
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;

const int MAXN = 210;

struct State
  {
int len,pos,now;
 State(int len,int pos,int now):len(len),pos(pos),now(now) {}
bool operator<(const State &B)const //選長度長的,長度相同的話選位置靠后的
 {
if(len==B.len)return pos<B.pos;
return len<B.len;
}
};

char str[MAXN],dig[MAXN];

int main()
  {
//freopen("in","r",stdin);
int T,t=1;
for(scanf("%d",&T);T--;)
 {
scanf("%s%s",str,dig);
stack<int>S;
S.push(0);
priority_queue<State>positive,negative;
for(int i=0;str[i];i++)
 {
if(str[i]=='(')
 {
if(i==0||str[i-1]=='(')S.push(S.top());
continue;
}
if(str[i]==')')
 {
S.pop();
continue;
}
if(str[i]!='#')
 {
S.push(S.top()^(str[i]=='-'));
continue;
}
if(i==0||str[i-1]=='(')S.push(S.top());
int len = 0,start = i;
while(str[i]=='#')i++,len++;
i--;
if(S.top())negative.push(State(len,-start,0));//-start 為了使前面的反而位置靠后
else positive.push(State(len,start,0));
S.pop();
}
sort(dig,dig+strlen(dig));
int ans = 0;
int beg=0,end=strlen(dig)-1;
while(!positive.empty())
 {
State top=positive.top();positive.pop();
top.now=top.now*10+dig[end]-'0';
str[top.pos]=dig[end--];
top.pos++;
top.len--;
if(top.len==0)ans+=top.now;
else positive.push(top);
}
while(!negative.empty())
 {
State top=negative.top();negative.pop();
top.now=top.now*10+dig[beg]-'0';
str[-top.pos]=dig[beg++];
top.pos--;
top.len--;
if(top.len==0)ans-=top.now;
else negative.push(top);
}
printf("Case %d:\n",t++);
puts(str);
printf("%d\n",ans);
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|