[JZOJ3588]【中山市选2014】J语言(表达式解析+栈)
Description
J语言作为一门编程语言,诞生于20世纪90年代..............
好学的小H今天又学到了一种新东西——J语言。显然,J语言的背景已经被小H忘得一干二净了,但是小H仍然记得J语言中有趣的数学计算——向量计算。
在J语言中,向量,标量和操作符是基本的组成元素,但是在小H的印象中,J语言中最有趣的就是它的语法,好学的小H也曾经认真研究J语言的语法并且进行了化简。在小H简化了J语言的语法中,用X来表示向量,用N来表示向量X的长度。
简化版J语言的规则如下:
操作符中有有二元操作符,“+”,“-”,“*”,而对应操作数可以是两个标量,两个向量,或则一个标量和一个向量。(当两个向量运算时,为对应位分别计算,例如(1,2,3) * (2,3,4) = (2,6,12),当一个标量和一个向量运算时,当成标量和向量的每一位运算,例如(1,2,3) * 5 = (5,10,15)
操作符中也有一元操作符,包括负数运算符“-”和平方运算符“*:”,其操作数可以为标量和向量。(向量取平方运算符时表示为每一位都取平方,例如*:(1, 2, 3) = (1, 4, 9),标量取平方时即数学意义上的平方,例如*:4 = 16)
求和运算符“+/”,该运算符只能作用于向量,能让向量求和为标量,例如+/(1,2,3) = 6
J操作符的运算顺序为从右到左,并且忽略优先级,需要优先计算的部分将用括号改变优先顺序(允许嵌套括号)。
小H化简的J语言还有一个限制——最高阶数的限制,我们这样定义一个表达数的阶数:
标量(数字, 'N' ,求和运算符“+/”的结果)的阶数为0;'X'的复杂度为1 ;加减法的阶数是其操作数的阶数的最大值;乘法的阶数是其操作数的阶数的总和;
一元平方的阶数是其操作数的阶数的两倍。
例如,表达式“(3-+/*:*:X)-X**:X”的阶数是3 ,而它的子表达式“*:*:X”的阶数是4 。
小H找到了一道以前写过简化版J语言的表达式,但是别忘了小H只是喜欢思考而不喜欢计算。现在,小H想请你帮他计算一下给定表达式的答案,并且将最终答案取模10^9(必须保证结果非负,即如果求余后是负数要加上10^9), 当然小H还清晰的记得他写下的表达式在运算过程中阶数不会超过10。
Main
给你一个式子和向量,按照规则进行运算,并求其结果。
Analysis
考虑到阶数比较小,可以用系数和次数来表示一个多项式。于是记录各个以x为主元的次数(0~10)其系数,设其为P。
因为常数项和多项式有诸多不同,想办法将他们归为一类、所以,常数项表示为{x,0,0,0,0,....},多项式表示为{x,x,x,x,x,x...},其实x代表任何数。
可能存在常数项与多项式的运算,考虑一种不同类型数之间计算的相似的计算方法。可以0次方项系数为向量各个位置的常数项,这样可以方便运算。
必要可以将两个字符长度的符号转成一个长度符号的。
Solution
预处理出Xk向量每个点的和,加减直接算即可,乘法平方可以10*10来计算,求和用预处理来算
讲一下大概流程,我用递归做的,这个递归代表一个各个次的系数
1、一开始求出当前递归函数的初始值,例如数字,N,X,括号内包含的
2、先看看是否有(-,+/,*:)。
3、这之后就是双元运算,先记录符号,往下找符合条件的值,如1。
略微不懂可以看例子,设X={2,3}
{5,7}*{3,4}
=(2X+1)*(X+1)
=2X²+3X+1
X²=13,X=5,所以原式=2*13+3*5+1*2=43,这与5*3+4*7有异曲同工之妙
Code
{$inline on} {$M 1000000,0,maxlongint}//扩大系统栈,不会打人工的 const maxn=1000000000; type arr=array[0..10] of int64; var now:int64; s:ansistring; s1,s2:string[1]; n,i,j,o,xi:longint; sum:array[0..10] of int64; p,last:array[0..10] of int64; a,l,pre,zhan:array[0..100000] of int64; function dg(l,r:longint):arr; inline; var k:longint; wait:string[1]; begin k:=r; fillchar(dg,sizeof(dg),0); if s[k]='X' then begin dg[1]:=1; dec(k); end else if s[k]='N' then begin dg[0]:=n; dec(k); end else if s[k]=')' then begin dg:=dg(pre[k]+1,k-1); k:=pre[k]-1; end else if (ord(s[k])>=48) and (ord(s[k])<=57) then begin now:=0; xi:=1; while (k>0) and (ord(s[k])>=48) and (ord(s[k])<=57) do begin now:=now+(ord(s[k])-48)*xi; xi:=xi*10; dec(k); end; dg[0]:=now; end;//初始值 wait:=''; while k>=l do begin if s[k]='^' then begin fillchar(last,sizeof(last),0); for i:=0 to 10 do if dg[i]<>0 then for j:=0 to 10 do if dg[j]<>0 then last[i+j]:=(last[i+j]+dg[i]*dg[j]) mod maxn; dg:=last; dec(k); continue; end; if s[k]='#' then begin now:=dg[0]*n; for i:=1 to 10 do now:=(now+sum[i]*dg[i]) mod maxn; fillchar(dg,sizeof(dg),0); dg[0]:=now; dec(k); continue; end; if (s[k]='-') and not (s[k-1] in ['X','N',')','0'..'9']) then begin for i:=0 to 10 do dg[i]:=-dg[i]; dec(k); continue; end;//一元运算符 wait:=s[k]; dec(k); fillchar(p,sizeof(p),0); if s[k]='X' then begin p[1]:=1; dec(k); end else if s[k]='N' then begin p[0]:=n; dec(k); end else if s[k]=')' then begin p:=dg(pre[k]+1,k-1); k:=pre[k]-1; end else if (ord(s[k])>=48) and (ord(s[k])<=57) then begin now:=0; xi:=1; while (k>0) and (ord(s[k])>=48) and (ord(s[k])<=57) do begin now:=now+(ord(s[k])-48)*xi; xi:=xi*10; dec(k); end; p[0]:=now mod maxn; end; if wait='+' then for i:=0 to 10 do dg[i]:=(dg[i]+p[i]) mod maxn; if wait='-' then for i:=0 to 10 do dg[i]:=(p[i]-dg[i]) mod maxn; if wait='*' then begin fillchar(last,sizeof(last),0); for i:=0 to 10 do if dg[i]<>0 then for j:=0 to 10 do if p[j]<>0 then last[i+j]:=(last[i+j]+dg[i]*p[j]) mod maxn; dg:=last; end; wait:=''; end; end; begin assign(input,'s.in');reset(input); readln(n); for i:=1 to n do begin read(a[i]); l[i]:=a[i]; end; readln; sum[0]:=1; for i:=1 to 10 do for j:=1 to n do begin sum[i]:=(sum[i]+l[j]) mod maxn; l[j]:=l[j]*a[j] mod maxn; end; readln(s); while (s[1]='(') and (s[length(s)]=')') do begin delete(s,1,1); delete(s,length(s),1); end; o:=1; s1:='#'; while o<=length(s)-1 do begin if (s[o]='+') and (s[o+1]='/') then begin delete(s,o,2); insert(s1,s,o); end; inc(o); end; o:=1; s2:='^'; while o<=length(s)-1 do begin if (s[o]='*') and (s[o+1]=':') then begin delete(s,o,2); insert(s2,s,o); end; inc(o); end;//替换符号长度为2的 for i:=length(s) downto 1 do //预处理括号位置 if s[i]=')' then begin inc(zhan[0]); zhan[zhan[0]]:=i; end else if s[i]='(' then begin pre[zhan[zhan[0]]]:=i; dec(zhan[0]); end; last:=dg(1,length(s)); writeln((last[0]+maxn*10) mod maxn); end.