一元一次方程

一元一次方程–逆波兰+栈

【题目摘要】
题目描述
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

输入格式
The first line of input contains the expression A (1 ≤|A|≤ 100000).

The second line of input contains two integers P (0 ≤ P ≤ M −1) i M (1 ≤ M ≤ 1000000).

The arithmetic expression A will only consists of characters +, -, *, (, ), x and digits from 0 to 9.

The brackets will always be paired, the operators +, - and * will always be applied to exactly two values (there will not be an expression (-5) or (4±5)) and all multiplications will be explicit (there will not be an expression 4(5) or 2(x)).

输出格式
输出最小的非负x

样例
样例输入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

【思路+正解】

部分小细节处理会在代码中体现并解释
首先看见这个带括号的中缀式 二话不说掏出 葵花宝典 前缀式or后缀式模板
它们的小跟班–小栈栈也会出现
woc前缀式or后缀式是神马玩意儿
只需要打开手机电脑搜索 你最喜欢的小姐姐小哥哥pick 她(他)吧 在这里插入图片描述
前缀式和后缀式有许多好文章可以帮助你理解

【概括一下】从左到右遍历中缀表达式的每个数字和符号,若是数字就不管,直接入栈;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈 并将当前符号进栈,

如此一来只要你有模板在手天下你有
(咳咳咳–回归正题 怎么想到后缀式的)
思考一下最后计算完的式子f(x) = kx + b
这个时候你就可以令x为零
算出f(0)也就是b的值
还可以算出令x为一f(1)也就是k+b的值结合上面已经算出的b的值就可以暴力求出了k的值那么x就自然而然出来了
如何计算f(0)和 f(1)的表达式,当然得用栈把中缀表达式改为后缀表达式!
所以总结套路:见中缀一定要想后缀和前缀

码力有限瞅瞅【代码实现】

#include <cstring>
#include <cstdio>
#include <stack>
using namespace std;
#define LL long long
#define MAXN 100005
struct node {
	LL a, b; //a为x系数 b为常数 
	node () {}
	node ( LL A, LL B ) {
		a = A;
		b = B;
	}
};
stack < char > mark; //存运算符 
stack < node > constant; //存常数 
int p, m, len;
char s[MAXN]; 

bool check ( char x, char y ) {
	if ( x == '(' || y == '(' ) return 0;
	if ( x == '*' || y == ')' || y == '+' || y == '-' ) return 1;
	return 0;
}

node count ( node x, node y, char z ) {
	node ans;
	switch ( z ) {
	//通过题目了解到x一定是一次项所以在算乘法的时候x,y两个当中一定有一个的系数为0
	//(kx+b)*a这种类似的就直接加不影响结果实在理解不了举个栗子就可以啦!
		case '*' : ans.a = ( x.a * y.b + x.b * y.a ) % m;ans.b = ( x.b * y.b ) % m;break;
		case '+' : ans.a = ( x.a + y.a ) % m;ans.b = ( x.b + y.b ) % m;break;
		case '-' : ans.a = ( y.a - x.a + m ) % m;ans.b = ( y.b - x.b + m ) % m;break;
		/**减法一定不要写成x.a-y.a因为think about it我们用的是栈先进后出
		我们传过来的参数(看下面)x在y前面那么反推它就是中缀式的减数**/
		//减法有可能简称负数因此要加一个mod
	}
	return ans;
}
 
int main() {
	scanf ( "%s", s );
	scanf ( "%d %d", &p, &m );
	len = strlen ( s );
	s[len] = ')';/*随便一个正确的式子最后一个肯定是数字或者x那么我们后面的代码
	无法让它参与到大家庭的计算当中就在最后加个右括号逼着它join*/
	mark.push ( '(' );
	for ( int i = 0;i <= len;i ++ ) {
		if ( s[i] == 'x' ) {
			constant.push ( node ( 1, 0 ) );
		}
		else if ( s[i] >= '0' && s[i] <= '9' ) {
				LL x = s[i] - '0';
				while ( s[i + 1] >= '0' && s[i + 1] <= '9' ) {
					i ++;
					x = ( ( x << 1 ) + ( x << 3 ) + ( s[i] - '0' ) ) % m;
				}
				constant.push( node ( 0, x ) );
			}
			else {
				while ( check ( mark.top(), s[i] ) ) {
					node x = constant.top();
					constant.pop();
					node y = constant.top();
					constant.pop();
					char z = mark.top();
					mark.pop();
					node result = count ( x, y, z );
					constant.push( result );
				}
				if ( s[i] == ')' ) mark.pop();
				/*如果是右括号check会一直返回1我们就会一直计算直到碰见它的另一半
				 ~~多么痴情一男的~~ 那么跳出while后就把这个左括号踢出去~它已经失宠了*/
				else mark.push( s[i] );
			}
	}
	node result = constant.top();
	//p一定小于m所以x一定不为0不然这就是个戴了面具的方程
	for ( LL i = 1;;i ++ )//可以暴力美剧如果前面写得好就可以不用担心
		if ( ( result.a * i + result.b ) % m == p )
			return ! printf ( "%lld", i );
	return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值