2019暑假七考~~一元一次方程[slon]~~(中缀转后缀求值,你从未见过的全新操作)


题目(1000ms)

描述
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+3x+4(5+3(2+x2x)).

不合理表达式 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 AP(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 1A100000,0PM1,1M1000000
注意, ∣ 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


Code
#include <map>
#include <stack>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
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)
*/


代码实现Tips
  • 中缀转后缀求值全新模板,你值得拥有
  • 因为最后要把字符栈中所有字符全弹出,所以你阔以手动再原字符串两边加括号
资源链接:[C++坐标换源代码实现](https://wenku.youkuaiyun.com/doc/1h5r7hza3q?utm_source=wenku_answer2doc_content) 在计算机图形学和地理信息系统领域,坐标换是一个复杂但必要的技术。为了解决如何在C++中实现GIS坐标系换并通过对话框展示结果的问题,首先需要明确坐标换的数学模型和在Windows环境下使用MFC库实现用户交互的步骤。 首先,坐标换通常涉及到复杂的数学运算,如仿射变换、投影变换等。这些运算需要在C++中编写算法来实现。在MFC中,可以通过继承 `CDialog` 类来创建一个对话框界面,用于输入和展示坐标值。 接下来,使用 `DDX_Control` 宏将对话框中的控件与类的成员变量关联起来,以便在程序运行时能够读取和更新这些控件的值。例如,你可以将一个编辑框与一个C++变量关联起来,用户在编辑框中输入的坐标值将直接反映到该变量中。 在《C++坐标换源代码实现》这一资源中,可以找到关于如何初始化数据、交换数据、使用DEBUG_NEW进行调试以及对话框控件与类变量关联的具体实现方法。这些内容对于理解如何在Windows环境下通过C++实现坐标换具有重要意义。 此外,实现坐标换的关键是定义换函数。换函数会根据特定的数学模型来计算新的坐标值。例如,如果你需要从WGS84坐标系换到UTM坐标系,你需要根据换公式来实现这个过程,并将计算结果输出到对应的对话框控件中。 假设你有一个换函数 `ConvertWGS84ToUTM`,它的作用是将WGS84坐标系下的点换到UTM坐标系。你可以在对话框类的某个事件处理函数中调用这个换函数,并将换结果更新到对话框控件中,供用户查看。 以下是一个简化的示例代码片段,展示了如何在用户点击换按钮后,获取输入的WGS84坐标,调用换函数,并显示UTM坐标结果的过程: ```cpp void CYourDialog::OnBnClickedConvert() { // 假设m_sLat和m_sLon是用户输入的纬度和经度,它们是类的成员变量 double lat = m_sLat; // 用户输入的纬度值 double lon = m_sLon; // 用户输入的经度值 // 调用换函数,假设函数返回一个包含UTM坐标的结构体 UTMCoordinate utmCoord = ConvertWGS84ToUTM(lat, lon); // 将换后的坐标更新到对话框控件中 UpdateData(TRUE); // 从成员变量更新控件数据 // 代码更新对话框中显示UTM坐标的控件 UpdateData(FALSE); // 反之从控件更新到成员变量 } // 以下是换函数的简化示例,实际的换过程会更复杂 UTMCoordinate ConvertWGS84ToUTM(double lat, double lon) { UTMCoordinate coord; // 在这里实现WGS84到UTM的换算法 // ... return coord; } ``` 在这个示例中,`OnBnClickedConvert` 函数会在用户点击换按钮时被调用。它从对话框控件中获取纬度和经度值,调用换函数,并将结果显示在对话框中。 要深入学习坐标换的C++实现,包括更复杂的换算法和Windows GUI编程,我强烈推荐你查阅《C++坐标换源代码实现》这一资源。它不仅包含实用的源代码,还详细解释了每个步骤,帮助你更好地理解和运用坐标换技术。 参资源链接:[C++坐标换源代码实现](https://wenku.youkuaiyun.com/doc/1h5r7hza3q?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值