SLON----不同于正解的中缀递归法

题目描述

SLON是一个调皮的学生,为了让他静下心来,老师给他出了一道数学题:

给定表达式A,A中含有变量x和+,-,*,(,)这些符号,括号成对出现,一个算术运算符均对应两个操作数,不能出现(-5)或者(4+-5)等,乘号不能省略,并且表达式A中x只能是一阶,即一阶表达式:

合理表达式:A=5 + x∗(3 + 2) or x + 3∗x + 4∗(5 + 3∗(2 + x−2∗x)).

不合理表达式:A=5∗(3 + x∗(3 + x)) or x∗(x + x∗(1 + x)).

求A%M==P时,最小的x

输入

第一行输入一个表达式A,(1 ≤|A|≤ 100000)。

第二行输入两个整数P (0 ≤ P ≤ M −1)和M (1 ≤ M ≤ 1000000)。

输出

输出最小的非负x (0 ≤ x ≤ 1000000)。

样例输入1

5+3+x

9 10

样例输出1

1

样例输入2

20+3+x

0 5

样例输出2

2

样例输入3

3*(x+(x+4)*5)

1 7

样例输出3

1


思路

这道题本来是用后缀来做的,坚定操守的朋友请看老师的正解

我们先想:A是一个一阶表达式(一次函数)吧,

初中数学里讲了,一个一次函数可以表达成 kx+b 的形式,比如样例一可以表达成 x+8,样例二可以表达成 x+23,样例三可以表达成 18x+60 。

那么只要求到了这个k和b,由于0 ≤ x ≤ 1000000,就能暴力枚举(也可以用扩欧,那样快些)。

接下来就是本题的精髓:把贼复杂的表达式A缩成 kx+b 。

我们可以先用分块的思想:因为加减法是最后计算的,所以把A分成若干部分相加的和,那么是不是每一个部分都能表示成 kx+b 的形式呢?(显然)

用函数 ins() 来把一个式子变为 kx+b,那么由于把A分成多少份是不确定的,最好用一个动态数组vector储存每个部分,当遇到一个数或一个x时,如果前面是“+”或“-”,就把它加进去(减法就加个负号);如果前面是“*”,就把数组最后一位乘上它。

当遇到“(”时,就递归进去,把括号内的式子 ins() 成一个 kx+b ,然后跟前面一样的操作。

这个乘法操作需要特别讨论一下:当两个 kx+b 相乘时,肯定有一个的 k 是零(因为题目保证x的次数为1),所以相当于一边的k和b同时乘上一个常数。

还有一点,因为题目没说明A里面的数有多大,所以可能爆longlong,要边操作边把数模m,不影响结果。

具体操作及细节请看下面的代码

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#define ll long long
using namespace std;
ll k,b,p,m;
int l;
string ss;
struct itn{
	ll k,b;
	itn(){}itn(ll K,ll B){
	k=(K+m)%m,b=(B+m)%m;
	}
	itn operator+(const itn&c){return itn(k+c.k,b+c.b);}
	itn operator*(const itn&c){
		if(k==0)return itn(c.k*b,c.b*b);
		else return itn(k*c.b,b*c.b);
	}
};
char s;
itn ins(){
	vector<itn>g;
	itn an=itn(0,0);
	int f=0;
	while(l<=ss.length()&&s&&s!=')'){
		if(s>='0'&&s<='9'){
			ll x=0;
			while(l<=ss.length()&&s>='0'&&s<='9')x=(x*10+s-'0')%m,s=ss[l++];//l=ss.length()时返回的为'\0'
			if(f==0)g.push_back(itn(0,x));
			else if(f==1)g.push_back(itn(0,-x));
			else {
				int o=g.size()-1;
				g[o]=g[o]*itn(0,x);
			}
		}
		else if(s=='x'){
			if(f==0)g.push_back(itn(1,0));
			else if(f==1)g.push_back(itn(-1,0));
			else {
				int o=g.size()-1;
				g[o]=g[o]*itn(1,0);
			}
			if(l<=ss.length())s=ss[l++];
		}
		else if(s=='+'){
			f=0;
			if(l<=ss.length())s=ss[l++];
		}
		else if(s=='-'){
			f=1;
			if(l<=ss.length())s=ss[l++];
		}
		else if(s=='*'){
			f=2;
			if(l<=ss.length())s=ss[l++];
		}
		else if(s=='('){
			if(l<=ss.length())s=ss[l++];
			itn x=ins();
			if(f==0)g.push_back(x);
			else if(f==1)g.push_back(itn(-x.k,-x.b));
			else {
				int o=g.size()-1;
				g[o]=g[o]*x;
			}
			if(l<=ss.length())s=ss[l++];
		}
	}
	for(int i=0;i<g.size();i++)an=an+g[i];
	return an;
}
int main()
{
	//freopen("slon.in","r",stdin);
	//freopen("slon.out","w",stdout);
	cin>>ss;
	scanf("%lld%lld",&p,&m);
	s=ss[l++];
	itn a=ins();
	k=a.k,b=a.b;
	//printf("A=%lldx+%lld\n",k,b);
	for(ll x=0;x<=1000000;x++)
		if(x*k+b>=0&&(x*k+b)%m==p){
			printf("%lld\n",x);
			return 0;
		}
	puts("100000");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43960287/article/details/97132073