slon
题目描述
S
L
O
N
SLON
SLON是一个调皮的学生,为了让他静下心来,老师给他出了一道数学题:
给定表达式
A
A
A,
A
A
A中含有变量
x
x
x和
+
,
−
,
∗
,
(
,
)
+,-,*,(,)
+,−,∗,(,)这些符号,括号成对出现,一个算术运算符均对应两个操作数,不能出现
(
−
5
)
(-5)
(−5)或者
(
4
+
−
5
)
(4+-5)
(4+−5)等,乘号不能省略,并且表达式
A
A
A中
x
x
x只能是一阶,即一阶表达式:
合理表达式
A
=
{
5
+
x
∗
(
3
+
2
)
x
+
3
∗
x
+
4
∗
(
5
+
3
∗
(
2
+
x
−
2
∗
x
)
)
A=\left\{\begin{array}{c}5 + x∗(3 + 2)\\x + 3∗x + 4∗(5 + 3∗(2 + x−2∗x))\end{array}\right.
A={5+x∗(3+2)x+3∗x+4∗(5+3∗(2+x−2∗x))
不合理表达式
A
=
{
5
∗
(
3
+
x
∗
(
3
+
x
)
)
x
∗
(
x
+
x
∗
(
1
+
x
)
)
.
A=\left\{\begin{array}{c}5∗(3 + x∗(3 + x))\\x∗(x + x∗(1 + x))\end{array}\right..
A={5∗(3+x∗(3+x))x∗(x+x∗(1+x)).
求
A
(
m
o
d
)
M
=
=
P
A(mod)M==P
A(mod)M==P时,最小的
x
x
x.
输入
第一行输入一个表达式
A
,
(
1
≤
∣
A
∣
≤
100000
)
A,(1≤|A|≤100000)
A,(1≤∣A∣≤100000)。
第二行输入两个整数
P
(
0
≤
P
≤
M
−
1
)
、
M
(
1
≤
M
≤
1000000
)
P (0 ≤ P ≤ M −1)、M (1 ≤ M ≤ 1000000)
P(0≤P≤M−1)、M(1≤M≤1000000)。
样例一
5+3+x
9 10
样例二
20+3+x
0 5
样例三
3*(x+(x+4)*5)
1 7
输出
输出最小的非负 x x x。
样例一
1
样例二
2
样例三
3
题解
一道十分经典的字符串处理四则运算题。
可以作为处理四则运算的典例。
首先,我们应该先搞清楚这个题的难点到底是什么。
其实看过题目都应该知道,处理字符串应该是这个题的核心难点。
至于什么取模什么相等的都去死吧,我要用爆搜之剑审判你
那么,这个有四则运算在其中的字符串应该如何处理呢?
那么,这里就有了许多种处理字符串的方式:
- 保持原有中则表达式,利用栈处理字符串
- 将中则表达式转为后缀表达式,利用栈与递归处理
(实在不知道这种思路叫什么)将每一个数字与一个运算符绑在一起,利用递归处理字符串。
这篇文章将侧重讲解第一种方法 (不然为什么把它放在前面)
首先,我们来看一下这道题处理麻烦的原因:
- 括号改变计算顺序
- 字符 x x x既不是运算符
- 括号前若有 ′ − ′ '-' ′−′,那么括号里面的所有符号(除乘号)都要进行反转操作
- ′ ∗ ′ '*' ′∗′与 ′ + ′ ( ′ − ′ ) '+'('-') ′+′(′−′)一起时,应先计算乘号的内容
也就是说,如果我们把以上问题处理好,那么此题就迎刃而解了。
要解决以上问题,这里要用一种封装思想:
这道题题目似乎很难,但是可以浓缩为几句话
将一个四则表达式化简为
K
x
+
B
Kx+B
Kx+B,且使得
(
K
x
+
B
)
m
o
d
M
=
=
P
(Kx+B)modM==P
(Kx+B)modM==P这就是这道题的精髓。
也就是说,我们要得到的是
K
K
K与
B
B
B,而所谓封装,就是将每一个括号(也不一定是括号)的
K
K
K与
R
R
R装进一个
s
t
r
u
c
t
struct
struct或者是
p
a
i
r
pair
pair中,再用这个
s
t
r
u
c
t
struct
struct或者
p
a
i
r
pair
pair与其他的直接进行加、减、乘即可。(这句话十分重要,但若是不懂,看看代码应该也能理解)
剩下的,和一般的四则运算处理就差不多了。
那么我们定义:
p
a
i
r
pair
pair中的
f
i
r
s
t
first
first为当前算式中
x
x
x的系数,
s
e
c
o
n
d
second
second为常数的值。
通过
p
a
i
r
pair
pair的两个数的定义,很容易就可以得出两个
p
a
i
r
pair
pair相加、减、乘时的具体操作。
为了更方便理解,这里我用数学符号进行推到(其实十分简单)
通过
p
a
i
r
pair
pair定义,令
p
a
i
r
1
=
(
K
1
,
B
1
)
pair_1=(K_1,B_1)
pair1=(K1,B1),
p
a
i
r
2
=
(
K
2
,
B
2
)
pair_2=(K_2,B_2)
pair2=(K2,B2).
那么
p
a
i
r
1
±
p
a
i
r
2
=
(
K
1
x
+
B
1
)
±
(
K
2
x
+
B
2
)
pair_1±pair_2=(K_1x+B_1)±(K_2x+B_2)
pair1±pair2=(K1x+B1)±(K2x+B2)
=
>
p
a
i
r
r
e
t
u
r
n
=
(
K
1
±
K
2
,
B
1
±
B
2
)
=>pair_{return}=(K_1±K_2,B_1±B_2)
=>pairreturn=(K1±K2,B1±B2)紧接着
p
a
i
r
1
∗
p
a
i
r
2
=
(
K
1
x
+
B
1
)
(
K
2
x
+
B
2
)
pair_1*pair_2=(K_1x+B_1)(K_2x+B_2)
pair1∗pair2=(K1x+B1)(K2x+B2)
=
>
原
式
=
K
1
K
2
x
2
+
(
K
1
+
K
2
)
x
+
B
1
B
2
=>原式=K_1K_2x^2+(K_1+K_2)x+B_1B_2
=>原式=K1K2x2+(K1+K2)x+B1B2注意,因为题目保证这是一个一元一次的方程,那么
K
1
K_1
K1、
K
2
K_2
K2中必有一个为
0
0
0,那么就不用考虑
x
2
x^2
x2了,那么
p
a
i
r
r
e
t
u
r
n
=
(
K
1
B
2
+
K
2
B
1
,
B
1
B
2
)
pair_{return}=(K_1B_2+K_2B_1,B_1B_2)
pairreturn=(K1B2+K2B1,B1B2)其他的操作就比较简单了。
下见代码。
#include<cstdio>
#include<stack>
#include<cstring>
#include<utility>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pll;
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
inline LL read(){
#define cg (c=getchar())
LL x,f=1;char c;
while(cg<'0'||'9'<c)if(c=='-')f=-1;
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return x*f;
#undef cg
}
const LL MAXL=100000;
char str[MAXL|1];
LL P,M,len;
pll operator+(const pll& a,const pll& b){
//处理两个pair相加
return mp((a.ft+b.ft)%M,(a.sd+b.sd)%M);
}
pll operator-(const pll& a,const pll& b){
return mp((a.ft-b.ft+M)%M,(a.sd-b.sd+M)%M);
}
pll operator*(const pll& a,const pll& b){
return mp((a.ft*b.sd+a.sd*b.ft)%M,a.sd*b.sd%M);
}
bool isnum(char c){
return '0'<=c&&c<='9';
}
stack<char>ch;
stack<pll>sta;
bool cmpPrio(char a,char b){
if(a=='('||b=='(')return 0;
if(a=='*'||b=='+'||b=='-'||b==')')return 1;
return 0;
}
pll solve(pll a,pll b,char ord){
if(ord=='+')return a+b;
if(ord=='-')return a-b;
if(ord=='*')return a*b;
return mp(0,0);
}
int main(){
scanf("%s",str+1);
len=strlen(str+1);
P=read(),M=read();
str[++len]=')';
ch.push('(');
for(LL i=1;i<=len;++i){
// printf("i==%d\n",i);
if(str[i]=='x')sta.push(mp(1,0));
else if(isnum(str[i])){
LL num=str[i]^48;
while(isnum(str[i+1]))
num=((num<<1)+(num<<3)+(str[++i]^48))%M;
sta.push(mp(0,num));
}
else{
while(cmpPrio(ch.top(),str[i])){
pll x,y;
x=sta.top();
sta.pop();
y=sta.top();
sta.pop();
sta.push(solve(y,x,ch.top()));
ch.pop();
}
if(str[i]==')')ch.pop();
else ch.push(str[i]);
}
}
pll res=sta.top();
for(LL i=0;i<=M;++i)if((res.ft*i+res.sd)%M==P)
return !printf("%lld\n",i);
return 0;
}