题目描述
SLON是一个调皮的学生,为了让他静下心来,老师给他出了一道数学题:
给定表达式A,A中含有变量x和+,-,*,(,)这些符号,括号成对出现,一个算术运算符均对应两个操作数,不能出现(-5)或者(4+-5)等,乘号不能省略,并且表达式A中x只能是一阶,即一阶表达式:
合理表达式:A=5 + x∗(3 + 2) or x + 3∗x + 4∗(5 + 3∗(2 + x−2∗x)).
不合理表达式:A=5∗(3 + x∗(3 + x)) or x∗(x + x∗(1 + x)).
求A%M==P时,最小的x
输入
第一行输入一个表达式A,(1 ≤|A|≤ 100000)。
第二行输入两个整数P (0 ≤ P ≤ M −1)和M (1 ≤ M ≤ 1000000)。
输出
输出最小的非负x (0 ≤ x ≤ 1000000)。
样例输入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
思路
这道题本来是用后缀来做的,坚定操守的朋友请看老师的正解
我们先想:A是一个一阶表达式(一次函数)吧,
初中数学里讲了,一个一次函数可以表达成 kx+b 的形式,比如样例一可以表达成 x+8,样例二可以表达成 x+23,样例三可以表达成 18x+60 。
那么只要求到了这个k和b,由于0 ≤ x ≤ 1000000,就能暴力枚举(也可以用扩欧,那样快些)。
接下来就是本题的精髓:把贼复杂的表达式A缩成 kx+b 。
我们可以先用分块的思想:因为加减法是最后计算的,所以把A分成若干部分相加的和,那么是不是每一个部分都能表示成 kx+b 的形式呢?(显然)
用函数 ins() 来把一个式子变为 kx+b,那么由于把A分成多少份是不确定的,最好用一个动态数组vector储存每个部分,当遇到一个数或一个x时,如果前面是“+”或“-”,就把它加进去(减法就加个负号);如果前面是“*”,就把数组最后一位乘上它。
当遇到“(”时,就递归进去,把括号内的式子 ins() 成一个 kx+b ,然后跟前面一样的操作。
这个乘法操作需要特别讨论一下:当两个 kx+b 相乘时,肯定有一个的 k 是零(因为题目保证x的次数为1),所以相当于一边的k和b同时乘上一个常数。
还有一点,因为题目没说明A里面的数有多大,所以可能爆longlong,要边操作边把数模m,不影响结果。
具体操作及细节请看下面的代码
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#define ll long long
using namespace std;
ll k,b,p,m;
int l;
string ss;
struct itn{
ll k,b;
itn(){}itn(ll K,ll B){
k=(K+m)%m,b=(B+m)%m;
}
itn operator+(const itn&c){return itn(k+c.k,b+c.b);}
itn operator*(const itn&c){
if(k==0)return itn(c.k*b,c.b*b);
else return itn(k*c.b,b*c.b);
}
};
char s;
itn ins(){
vector<itn>g;
itn an=itn(0,0);
int f=0;
while(l<=ss.length()&&s&&s!=')'){
if(s>='0'&&s<='9'){
ll x=0;
while(l<=ss.length()&&s>='0'&&s<='9')x=(x*10+s-'0')%m,s=ss[l++];//l=ss.length()时返回的为'\0'
if(f==0)g.push_back(itn(0,x));
else if(f==1)g.push_back(itn(0,-x));
else {
int o=g.size()-1;
g[o]=g[o]*itn(0,x);
}
}
else if(s=='x'){
if(f==0)g.push_back(itn(1,0));
else if(f==1)g.push_back(itn(-1,0));
else {
int o=g.size()-1;
g[o]=g[o]*itn(1,0);
}
if(l<=ss.length())s=ss[l++];
}
else if(s=='+'){
f=0;
if(l<=ss.length())s=ss[l++];
}
else if(s=='-'){
f=1;
if(l<=ss.length())s=ss[l++];
}
else if(s=='*'){
f=2;
if(l<=ss.length())s=ss[l++];
}
else if(s=='('){
if(l<=ss.length())s=ss[l++];
itn x=ins();
if(f==0)g.push_back(x);
else if(f==1)g.push_back(itn(-x.k,-x.b));
else {
int o=g.size()-1;
g[o]=g[o]*x;
}
if(l<=ss.length())s=ss[l++];
}
}
for(int i=0;i<g.size();i++)an=an+g[i];
return an;
}
int main()
{
//freopen("slon.in","r",stdin);
//freopen("slon.out","w",stdout);
cin>>ss;
scanf("%lld%lld",&p,&m);
s=ss[l++];
itn a=ins();
k=a.k,b=a.b;
//printf("A=%lldx+%lld\n",k,b);
for(ll x=0;x<=1000000;x++)
if(x*k+b>=0&&(x*k+b)%m==p){
printf("%lld\n",x);
return 0;
}
puts("100000");
return 0;
}