描述
SLON是一个调皮的学生,为了让他静下心来,老师给他出了一道数学题:
给定表达式A,A中含有变量x和+,-,*,(,)这些符号,括号成对出现,一个算术运算符均对应两个操作数,不能出现(-5)或者(4±5)等,乘号不能省略,并且表达式A中x只能是一阶,即一阶表达式:
合理表达式 A = 5 + x ∗ ( 3 + 2 ) o r x + 3 ∗ x + 4 ∗ ( 5 + 3 ∗ ( 2 + x − 2 ∗ x ) ) . A=5 + x∗(3 + 2) or x + 3∗x + 4∗(5 + 3∗(2 + x−2∗x)). A=5+x∗(3+2)orx+3∗x+4∗(5+3∗(2+x−2∗x)).
不合理表达式 A = 5 ∗ ( 3 + x ∗ ( 3 + x ) ) o r x ∗ ( x + x ∗ ( 1 + x ) ) . A=5∗(3 + x∗(3 + x)) or x∗(x + x∗(1 + x)). A=5∗(3+x∗(3+x))orx∗(x+x∗(1+x)).
求 A ≡ P ( m o d M ) A \equiv P\pmod M A≡P(modM)时,最小的x
输入
The first line of input contains the expression A .
The second line of input contains two integers P , M .
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 ≤ ∣ A ∣ ≤ 100000 , 0 ≤ P ≤ M − 1 , 1 ≤ M ≤ 1000000 1 ≤|A|≤ 100000,0 ≤ P ≤ M −1,1 ≤ M ≤ 1000000 1≤∣A∣≤100000,0≤P≤M−1,1≤M≤1000000
注意, ∣ A ∣ |A| ∣A∣是指字符串 A A A的长度
样例
样例输入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
大体思路
应为最后的表达式一定是 f ( x ) = k x + b f(x)=kx+b f(x)=kx+b,所以我们可以分别求出
f ( 0 ) f(0) f(0)和 f ( 1 ) f(1) f(1), f ( 0 ) = b , f ( 1 ) = k + b f(0)=b, f(1)=k+b f(0)=b,f(1)=k+b,这样我们就可以求出 k k k和 b b b,最后暴力枚举或者求逆元随便
实现时的思路
由于题目是中缀表达式,计算起来比较复杂,所以我们需要把中缀表达式转为后缀表达式
当然,如果你觉得你能够计算中缀表达式,Orz,但是,这道题神仙数据,像()+x,(x)+(344)+(13566),(((((((x)))))))等等,加油,我相信你
大佬可以略过下面两篇博客
中缀转后缀
中缀转后缀并求值
最后求答案时,直接暴力枚举或者求逆元(忘得差不多了,好多方法)
由于我觉得中缀转后缀再求值太麻烦,所以我在转后缀的同时就计算了。
题目不就是求一个系数和常数么?那就存两个栈,求常数的那个栈就把x存为0,其他数原封不动存入栈中;求系数的那个栈就把x存为1,其他数存为0,加减法时就用本栈里的数,在做乘法的时候,若其中只有一个数为0,那么就乘上另一个栈里对应的数(两栈同时计算),若两数都为零,那没办法,push(0)。(搞了很久啊)
最后两栈中一个就是常数 ( b ) (b) (b),一个就是系数 ( k ) (k) (k),再用之前的办法求出 a n s ans ans就行了
注意,最后的数可能很大,操作的时候记得 % m \% m %m,
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
map<char, bool>Level;
stack<char>S;//字符
stack<LL>num[2];//num[0]存常数,num[1]存系数
string s;
int l;
LL _x, _sum, p, m, tot;
inline void calc(char cc){
LL a = 0, b = 0, a1 = 0, b1 = 0;
a = num[0].top();
num[0].pop();
b = num[0].top();
num[0].pop();
a1 = num[1].top();
num[1].pop();
b1 = num[1].top();
num[1].pop();/*
printf("%c\n", cc);
printf("%d %d\n", a1, b1);*/
if( cc == '*' ){//乘法有特例
num[0].push(a*b%m);
if( a1 == 0 && b1 != 0 )
num[1].push(a*b1%m);
if( a1 != 0 && b1 == 0 )
num[1].push(a1*b%m);
if( a1 != 0 && b1 != 0 )
num[1].push(a1*b1%m);
if( a1 == 0 && b1 == 0 )
num[1].push(0);
}
if( cc == '-' ){
num[1].push((b1-a1+m)%m);
num[0].push((b-a+m)%m);
}
if( cc == '+' ){
num[1].push(a1+b1%m);
num[0].push(a+b%m);
}
}
int main(){
cin >> s;
s += ")";//手动加括号
scanf("%lld%lld", &p, &m);
l = s.length();
Level['-'] = Level['+'] = 0;
Level['*'] = 1;
Level['('] = Level[')'] = 2;
S.push('(');
for(int i = 0; i < l; i ++){
if( isdigit(s[i]) && !(i==0?0:isdigit(s[i-1])) ){//特殊情况
num[0].push(s[i]^48);
num[1].push(0);
}
else if( isdigit(s[i]) && (i==0?0:isdigit(s[i-1])) ){
LL sc = num[0].top();
num[0].pop();
num[0].push(sc*10%m+(s[i]^48)%m);
}
if( s[i] == 'x' ){
num[0].push(0);
num[1].push(1);
continue;
}
if( s[i] == '-' || s[i] == '+' || s[i] == '*' ){
while( !S.empty() && Level[s[i]] <= Level[S.top()] && S.top() != '(' ){
//printf("\n1 %c\n", s[i]);老祖调试法
calc(S.top());
S.pop();
}
S.push(s[i]);
}
if( s[i] == ')' ){
while( !S.empty() && S.top() != '(' ){
//printf("\n2\n");
if( S.top() == '-' || S.top() == '+' || S.top() == '*' )
calc(S.top());
S.pop();
}
S.pop();
}
if( s[i] == '(' )
S.push(s[i]);
}
_sum = num[0].top()%m, _x = num[1].top()%m;
while( tot < m ){//暴力
if( (tot*_x+_sum)%m == p ){
printf("%lld\n", tot);
break;
}
tot++;
}
return 0;
}
//(10)+(((3-4+5*7+x))+5*9-(4)*9-x*1+(x))
/*
((((((x+1)+1)+1)+1)+1)+1)
*/