题目描述
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 ) 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) or x+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)) or x∗(x+x∗(1+x))
求 A A%M==P A时,最小的 x x x
输入
第一行输入一个表达式 A A A, ( 1 ≤ ∣ A ∣ ≤ 100000 ) (1 ≤|A|≤ 100000) (1≤∣A∣≤100000)
第二行输入两个整数 P P P ( 0 ≤ P ≤ M − 1 ) (0 ≤ P ≤ M −1) (0≤P≤M−1)和 M M M ( 1 ≤ M ≤ 1000000 ) (1 ≤ M ≤ 1000000) (1≤M≤1000000)
输出
输出最小的非负 x x x
样例输入
5+3+x
9 10
样例输出
1
这个题其实考试时想到了,但细节好像有点多。。。
这个题思路很简单,把字符串处理出来,暴力答案(考试时还以为是拓展欧几里得,结果忘了怎么求二元一次不定方程的通解,然后果断暴力居然撞上了正解 好水呀 )
主要就是这个字符串处理比较细节,这个中缀表达式有点毒瘤。可以考虑把这个中缀转换成后缀,然后就可以处理了。我是直接搞的中缀
定义两个栈,一个存数字,一个存符号
数字没有什么好处理的,我就直接写符号的处理:
1、 ( ( ( 直接入栈
2、 + , − , ∗ +,-,* +,−,∗ 入栈时判断如果当前的栈顶为 ∗ * ∗,就将这个乘法运算处理掉
3、 ) ) ) 弹出栈中元素,直到弹到左括号,将弹出的符号预算全部处理
最后可以枚举答案,但拓展欧几里得明显会更快,在此讲一下:
题目给出的中缀表达式最终一定可以表示为 a x + b ax+b ax+b的形式
∵ ( a x + b ) % m = p ∴ a x + b = k m + p ⇒ a x − k m = p − b \because (ax+b)\% m=p\\ \therefore ax+b=km+p\\ \Rightarrow ax-km=p-b ∵(ax+b)%m=p∴ax+b=km+p⇒ax−km=p−b
至于求 a , b a,b a,b,我们只需要将 x = 0 和 x = 1 x=0和x=1 x=0和x=1代入原式,分别可得 b 和 a + b b和a+b b和a+b,然后就可以求出 a a a了
最后求符合条件的最优解即可
#include
#include
#include
#include
#include
using namespace std;
template <typename T>
T Fabs(T x) {return x < 0 ? -x : x;}
#define LL long long
const int N = 100005;
stack <int> sta1;
stack <char> sta2;
LL P, M, a1, a2, ansx, ansy;
int len;
char a[N];
int solve(int x) {
while(!sta1.empty()) sta1.pop();
while(!sta2.empty()) sta2.pop();
for(int i = 0; i <= len + 1; i ++) {
if(a[i] != ')') {
if(a[i] >= '0' && a[i] <= '9') {
LL num = a[i] - '0';
while(a[i + 1] >= '0' && a[i + 1] <= '9') {
num = (num * 10 + a[i + 1] - '0') % M;
i ++;
}
sta1.push(num);
}
if(a[i] == 'x')
sta1.push(x);
if(a[i] == '+' || a[i] == '-' || a[i] == '*') {
if(sta2.top() == '*') {
sta2.pop();
LL num1 = sta1.top();
sta1.pop();
LL num2 = sta1.top();
sta1.pop();
sta1.push(num1 * num2 % M);
}
sta2.push(a[i]);
}
if(a[i] == '(')
sta2.push('(');
}
else {
if(sta2.top() == '*') {
sta2.pop();
LL num1 = sta1.top();
sta1.pop();
LL num2 = sta1.top();
sta1.pop();
sta1.push(num1 * num2 % M);
}
while(!sta2.empty()) {
if(sta2.top() == '(') {
sta2.pop();
break;
}
else {
LL num1 = sta1.top();
sta1.pop();
LL num2 = sta1.top();
sta1.pop();
if(sta2.top() == '+')
sta1.push((num1 + num2) % M);
else if(sta2.top() == '-')
sta1.push((num2 - num1 + M) % M);
else
sta1.push(num1 * num2 % M);
sta2.pop();
}
}
}
}
return sta1.top();
}
LL exgcd(LL a, LL b, LL &x, LL &y) {
if(b == 0) {
x = 1, y = 0;
return a;
}
else {
LL ret = exgcd(b, a % b, y, x);
y -= x * (a / b);
return ret;
}
}
int main() {
scanf("%s", a + 1);
scanf("%lld%lld", &P, &M);
len = strlen(a + 1);
a[0] = '(', a[len + 1] = ')';
LL sol1 = solve(0);
LL sol2 = solve(1);
a1 = (sol2- sol1 + M) % M, a2 = sol1;
LL GCD = exgcd(a1, M, ansx, ansy);
ansx *= ((P - a2) / GCD);
while(ansx >= 0)
ansx -= M / GCD;
while(ansx < 0)
ansx += M / GCD;
printf("%lld\n", ansx);
return 0;
}