[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.

 

posted @ 2018-01-21 23:06  Philchieh  阅读(412)  评论(0编辑  收藏  举报