一元一次方程

一、题目

题意:
给定一个只含数字,运算符(不包含除号),和未知数 x x x的一阶表达式 A A A,求满足 A % m = p A\%m=p A%m=p x x x的最小非负数解。
数据范围:
表达式长度 ≤ 100000 , 1 ≤ p < m ≤ 1000000 \leq 100000,1\leq p100000,1p<m1000000数字可能存在高精

二、解法

首先它既然是一阶表达式,必然可以表示为 a x + b ax+b ax+b的形式,我们将 x = 0 , x = 1 x=0,x=1 x=0x=1分别带入求值即可得到这个式子,因为 m m m特别小,所以暴枚 x x x即可(如果 m m m大可以用扩展欧几里得 l o g log log求出答案)。
我们考虑怎么带入 x x x求值。
题目给出的是一个中缀表达式(方便人类理解),但因为它变化太多,计算机无法快速且固定的求解,我们就需要使用后缀表达式,也就是能够按线性顺序计算的表达式,具体来说,就是将每一个运算符前两个数计算,再合并成一个数继续跑(不用括号,可以用栈 O ( n ) O(n) O(n)解决),最后能得到相同解的表达式。
我们考虑怎么生成后缀表达式。(下文简称表达式)
(1)遇到数直接加入表达式(因为我们考虑的是运算符的顺序,不用管数字)。
(2)如果遇到’(’,直接加入栈。
(3)如果遇到’)’,删除栈顶直到查找到’(’,把删除运算符的加入表达式。(即我们优先计算括号里面的)
(4)如果是运算符,和栈顶元素比较,如果栈顶是’(‘则不删除,如果当前运算符是’+’’-‘则删除(即优先级最低,把前面的运算符放一堆计算,独立开来),在考虑如果当前和栈顶元素都为’*‘时删除,否则不删除,把删除运算符的加入表达式, w h i l e while while维护栈。
(5)最后清空栈,加运算符进表达式。
说的比较清楚了,本题还有一个问题,就是数可能为高精。
那我们就把数和数之间加入’.'符,在遇到运算符就向表达式加入,为了分隔数与数。还有本题要注意多去模,作者就是因为细节问题错了十几次。

终于口胡完了,还有问题看代码吧(无脑处理了两次,常数较大)。

#include 
#include 
#define LL long long
using namespace std;
const LL MAXN = 100005;
LL read()
{
    LL x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
LL n,m,p,mod,s[MAXN];
char a[MAXN],b[MAXN*2];
LL operate(LL a,LL b,char x)
{
    if(x=='+') return (a+b)%mod;
    if(x=='-') return (b-a+mod)%mod;//
    if(x=='*') return a*b%mod;
    return 0;
}
bool priority(char a,char b)
{
    if(b=='(') return 0;
    if(a=='+' || a=='-') return 1;
    if(a=='*' && b=='*') return 1;
    return 0;
}
void exchange()
{
    LL top=0;
    m=0;
    for(LL i=0;i<n;i++)
    {
        if((a[i]>='0' && a[i]<='9') || a[i]=='x')
            b[m++]=a[i];
        else if(a[i]==')')
        {
            while(top>0 && s[top]^'(') b[m++]=s[top--];
            top--;
        }
        else if(a[i]=='(' || a[i]=='+' || a[i]=='-' || a[i]=='*')
        {
            if(a[i]^'(')
            {
                b[m++]='.';
                while(top>0 && priority(a[i],s[top])) b[m++]=s[top--];
            }
            s[++top]=a[i];
        }
    }
    while(top>0) b[m++]=s[top--];
    return ;
}
LL calculate(LL val)
{
    LL top=0;
    for(LL i=0;i<m;i++)
        if(b[i]=='x')
            b[i]=val+'0';
    for(LL i=0;i<m;i++)
    {
        if(b[i]=='.') continue;
        if(b[i]=='+' || b[i]=='-' || b[i]=='*')
        {
            LL u=s[top],v=s[top-1];
            s[--top]=operate(u,v,b[i]);
        }
        else if(b[i]>='0' && b[i]<='9')
        {
            LL j=i,x=0;
            while(j<m && b[j]>='0' && b[j]<='9')
                x=(x<<3)+(x<<1)+(b[j++]^'0'),x%=mod;
            i=j-1;
            s[++top]=x;
        }
    }
    return s[top];
}
int main()
{
    scanf("%s",a);
    n=strlen(a);
    p=read();mod=read();
    exchange();
    LL B=calculate(0);
    exchange();
    LL A=((calculate(1)-B)+mod)%mod;
    for(LL i=0;i<mod;i++)
        if(((A*i+B)%mod+mod)%mod==p)
            return !printf("%lld\n",i);
}//x+3*x+4*(5+3*(2+x-2*x))

你可能感兴趣的:(表达式)