GYM100198G - PL/Cool

比较毒瘤的一道模拟。

首先,我们考虑如何处理 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
posted @ 2023-05-15 20:58  jucason_xu  阅读(16)  评论(0编辑  收藏  举报