jzoj3588 【中山市选2014】J语言 (表达式解析)
2018-01-20 17:30
218 查看
超长题面
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。
100%数据,n<=100000,长度<=100000
分析
一眼看,次数不超过10,那表达式肯定是以X为主元的多项式形式进行运算。但是一直在想如何兼容所有运算,其实是忽略了一个东西:
X^0={1,1,1,….}
这样可以把标量看作是{5,5,5,5,…}这样的向量,表示为多项式形式就是{5,0,0,0,0…},参与运算即可.
那就很简单了,加减法显然, 平方与乘法就类似多项式乘法,用10*10的时间做. 求和运算预处理一下X^k的各个位置和即可。
搞清楚运算怎么做之后,
再用一个栈,倒着扫(优先级从右到左)做表达式解析即可。 注意是可以存在类似–(..),–X这样的表达式的。
我的(代码复杂度被吊打)表达式解析大概思路:
遇到)入栈一个单位元素,单位元素与A运算都是A.
然后每次读入一个value(X或N或数字),与之前合并,再读入下一个操作符,假如是双目就存到wait等待合并,否则立即执行.
遇到(就将当前括号的元素(栈顶)与上一层元素(栈顶前一个)合并,并退栈.
#include <iostream> #include <cstring> #include <cstdio> #define VEC 1 #define EMP -666 #define NUM 2 using namespace std; typedef long long ll; const ll N = 100100,mo = 1e9; struct value{ ll a[11]; value() {memset(a,0,sizeof a);} } sd,v ,ept,LEN; ll n,sl,a ,b ; char ts ,s ; value ele ; ll tot,wait ,p; ll sum[10]; //1 + //2 - //3 * //4 *: //5 +/ int getop() { if (s[p]=='+') {p++; return 1;} if (s[p]=='-') {p++; return 2;} if (s[p]=='*') {p++; return 3;} if (s[p]==':') {p+=2; return 4;} if (s[p]=='/') {p+=2; return 5;} } value ret; value getva() { if (s[p]=='X') {p++; return sd;} if (s[p]=='N') {p++; return LEN;} int st=p; while (s[p]>='0' && s[p]<='9') p++; ret=value(); for (int i=p-1; i>=st; i--) ret.a[0]=ret.a[0]*10+s[i]-'0'; return ret; } value mult(value a,value b) { ret=value(); for (int i=0; i<=10; i++) for (int j=0; j<=10; j++) if (i+j<=10) { ret.a[i+j]=(ret.a[i+j]+a.a[i]*b.a[j])%mo; }else break; return ret; } value qf(value a) { for (int i=0; i<=10; i++) a.a[i]=-a.a[i]; return a; } value add(value a,value b) { ret=value(); for (int i=0; i<=10; i++) ret.a[i]=(a.a[i]+b.a[i])%mo; return ret; } value operate(value a,int type,value b) { if (b.a[0] == EMP) return a; if (type==1) return add(a,b); if (type==2) return add(a,qf(b)); if (type==3) return mult(a,b); } value operate(value a,int type) { if (type==4) return mult(a,a); if (type==5) { ll su=0; for (int i=0; i<=10; i++) su=(su+a.a[i]*sum[i])%mo; ret=value(),ret.a[0]=su; return ret; } } void getnexop() { while (s[p]!='(') { //此value前有操作符 int t=getop(); if (t<=3) { if (t==2 && s[p]=='-') { ele[tot]=qf(ele[tot]); continue; } wait[tot]=t; //双目操作符放入wait break; } else ele[tot]=operate(ele[tot],t); } } int main() { freopen("2.in","r",stdin); cin>>n; for (ll i=1; i<=n; i++) scanf("%lld",&a[i]); for (int i=1; i<=n; i++) b[i]=1; for (int i=0; i<=10; i++) { for (int j=1; j<=n; j++) { if (i) b[j]=b[j]*a[j]%mo; sum[i]=(sum[i]+b[j])%mo; } } sd.a[1]=1; LEN.a[0]=n; scanf("%s",ts+1); sl=strlen(ts+1); for (int i=1; i<=sl; i++) s[i]=ts[sl-i+1]; ele[++tot].a[0]=EMP; for (p=1; p<=sl;) { if (s[p]==')') { ele[++tot].a[0]=EMP; //新建空value p++; } else if (s[p]=='(') { if (wait[tot]==2) //先处理wait中的单目- ele[tot]=qf(ele[tot]),wait[tot]=0; //merge前一个ele ele[tot-1]=operate(ele[tot],wait[tot-1],ele[tot-1]); wait[tot-1]=0; tot--; p++; getnexop(); } else { value tv=getva(); // if (wait[tot]) 一定要合并 ele[tot]=operate(tv,wait[tot],ele[tot]); wait[tot]=0; getnexop(); } } if (wait[tot]==2) ele[tot]=qf(ele[tot]),wait[tot]=0; cout<<(ele[1].a[0]+mo)%mo<<endl; }
相关文章推荐
- jzoj 3587. 【中山市选2014】dwarf tower 暴力水题
- servlet接口及原理解析,表达式语言解析
- 设计自制编程语言Monkey编译器:使用普拉特解析法解析复杂的算术表达式
- [jzoj]3729. 【NOIP2014模拟7.10】表达式的值(exp) (分块转化模型)
- Java 8 动态类型语言Lambda表达式实现原理解析
- reactjs自制Monkey语言编译器:解析组合表达式,ifelse语句块和间套函数调用
- struts2.X心得15--OGNL表达式语言和struts标签案例解析
- 一种表达式语言的解析引擎JEXL简单使用
- struts2.X心得15--OGNL表达式语言和struts标签案例解析
- jzoj3587 【中山市选2014】dwarf tower
- 【JZOJ3598】【CQOI2014】数三角形
- 且看如何以精致的方式展现,解析和分析GitHub上语言的发展趋势
- JavaWeb学习笔记——表达式语言
- 解析四则表达式的编译过程及生成汇编代码
- 【第五章】Spring表达式语言 之 5.1 概述 5.2 SpEL基础 ——跟我学spring3
- 数学表达式解析工具
- 我从表达式语言角度对C#的看法
- 零基础学python-19.8 生成器表达式:当迭代器遇上列表解析
- 【第五章】Spring表达式语言 之 5.1 概述 5.2 SpEL基础 ——跟我学spring3
- 3ds Max 2014的Maxscript中使用正则表达式