比较毒瘤的一道模拟。
首先,我们考虑如何处理 define
,我们发现,其中不会出现环,并且所有冲突的定义以第一个为准,那么就想到并查集,将 \(x\) 的父亲定成 \(y\)。只不过我们平时的并查集是无向的,这里是有向的,也就是谁是根是重要的。
我们先给所有的定义和被定义的变量映射到一个值,然后用并查集维护,如果当前节点已经有父亲,或者 \(y\) 在 \(x\) 的子树中,就不连边。否则连边。
然后考虑计算答案。我们考虑中缀表达式。每次处理出当前第一个需要处理的符号,将原串划分成两个子问题递归计算。但是注意我们要按顺序进行,左边的优先级高,那么就从右边开始往下递归查找。反之亦然。递归直到没有运算符号。
同时,因为括号的优先级最高,所以我们维护当前递归了几层括号,在括号内部的运算忽略。如果整个子串被一个括号包含,要去掉。
我们先查找 +
和 -
,注意它们也有可能不是代数和符号而是表示正负号,这个时候要判断前面的字符是否是运算来判别。
然后是 */
和 %
。注意负数取模的定义,这道题是绝对值为绝对值取模,符号为二者符号相乘。
最后是 ^
,最好写一个快速幂,而且只有它是从前往后的。
别忘了处理掉作为符号的 +
和 -
,对最终的变量,如果表中有就直接找到它的值输出(注意在并查集上跑出父亲)。如果表中没有就临时转 int
,也不要存表,否则表长不好控制。注意判断含不含字母,如果是新变量要赋成 0
。
最后,大小写不敏感,可以把所有的字母输入之后统一成小写。输入也比较扯,因为表达式带空格。我是用的 getline
一次读入,然后用 stringstream
搞掉空格。
map<string,int>id;
string ss[60005];
int fa[60005],val[60005],cnt=0;
inline int sti(string s){
int ans=0;
for(auto i:s){
if((i<'0'||i>'9'))return 0;
ans=ans*10+i-'0';
}
return ans;
}
inline void add(string s){
if(!id.count(s)){
id[s]=++cnt;
ss[cnt]=s;val[cnt]=sti(s);
}
}
inline int head(int x){
return fa[x]?fa[x]=head(fa[x]):x;
}
inline int fpow(int x,int p){
if(!p)return 1;
int res=fpow(x,p>>1);
if(p&1)return res*res*x;
return res*res;
}
inline int mymod(int x,int y){
if((x<0)^(y<0))return -abs(x)%abs(y);
return abs(x)%abs(y);
}string s;
inline bool sig(int x){
return (s[x]=='+'||s[x]=='-'||s[x]=='*'||s[x]=='/'||s[x]=='%'||s[x]=='^');
}
inline int solve(int l,int r){
for(int i=r,cnt=0;i>l;i--){
cnt+=(s[i]==')')-(s[i]=='(');
if(!cnt){
if(s[i]=='+'&&!sig(i-1))return solve(l,i-1)+solve(i+1,r);
if(s[i]=='-'&&!sig(i-1))return solve(l,i-1)-solve(i+1,r);
}
}for(int i=r,cnt=0;i>l;i--){
cnt+=(s[i]==')')-(s[i]=='(');
if(!cnt){
if(s[i]=='*')return solve(l,i-1)*solve(i+1,r);
if(s[i]=='/')return solve(l,i-1)/solve(i+1,r);
if(s[i]=='%')return mymod(solve(l,i-1),solve(i+1,r));
}
}for(int i=l,cnt=0;i<r;i++){
cnt+=(s[i]=='(')-(s[i]==')');
if(!cnt){
if(s[i]=='^')return fpow(solve(l,i-1),solve(i+1,r));
}
}if(s[l]=='(')return solve(l+1,r-1);
if(s[l]=='+')return solve(l+1,r);
if(s[l]=='-')return -solve(l+1,r);
st t=s.substr(l,r-l+1);
if(!id.count(t))return sti(t);
return val[head(id[t])];
}
string ope,x,y;
signed main(){
freopen("plcool.in","r",stdin);
freopen("plcool.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>ope){
if(ope=="define"){
cin>>x>>y;
for(auto &i:x)if(isupper(i))i-='A',i+='a';
for(auto &i:y)if(isupper(i))i-='A',i+='a';
add(x);add(y);
int a=id[x],b=id[y];
if(!fa[a]&&head(b)!=a)fa[a]=b;
}else if(ope=="print"){
x="";
getline(cin,s);
istringstream ss(s);
while(ss>>y)x+=y;s=x;
for(auto &i:s)if(isupper(i))i-='A',i+='a';
cout<<solve(0,(int)s.size()-1)<<endl;
}else exit(-1);
}
return 0;
}
//Crayan_r
标签:cnt,return,fa,int,res,GYM100198G,solve,PL,Cool
From: https://www.cnblogs.com/jucason-xu/p/17403124.html