【vijos】1765 Caculator(代码题)

https://vijos.org/p/1765

这题用白书的方法是n^2的,所以我tle了一个点。。sad。

我稍微优化了一下。

这个题给我最大的感受不是这个题本身,而是我感受到了自己思考以后并认真查错一次提交获得这么高分的感受。

做题一定要认真、仔细。

写这些题最重要的就是仔细,一些细节方面没处理好,那么就会挂了,而陷入调试的泥潭。

想想我以前写的程序,哪个不是这样呢?

首先一定要有个大概的框架了且自己反复论证这样做是正确的(不考虑满分的情况下,可以充当暴力以便对拍和骗分)

一定要反复论证!

然后是在自己写的时候一定要专心,且一定要跟着框架走,如果发现自己之前想的是错的,一定先离开键盘,仔细的再想一遍。

当写完是否庞大的码量后,一定要静态查错,无疑是几个地方:变量名、数组、逻辑、sb错,且一定要反复验证自己代码的逻辑正确性。

之后才测样例。

一般是直接过的。

如果不过那么不要陷入调试的泥潭,一定要重新看一下哪里会错,哪里可能会错。然后对应的在那里调试,而对应的在那里调试那么就要看自己代码的分块性了,分块得好那么就易于调试。

好了。。

以后就这样,不要着急,要知道这是自己在战斗,只是为了解决问题,而不是一昧地去追求代码的美观,而是正确性。

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

#include <map>

#include <cassert>

using namespace std;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << (#x) << " = " << (x) << endl

#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }

#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const int min(const int &a, const int &b) { return a<b?a:b; }



map<string, int> mp;

typedef long long ll;

const int N=105, M=100005;

const ll eps=1e9;

int n, m, ID, a[N], flag, tot, db;

char s[15];

struct node { node *l, *r; bool f, opt; int s; node() { l=r=NULL; f=opt=0; s=0; } }*root=NULL;

struct dat { int s; bool f, opt; dat() { s=0; f=opt=0; } }b[M];

int getid(char *st, int len) {

	string s(st, len);

	if(mp[s]) return mp[s];

	mp[s]=++ID;

	return ID;

}

ll cal(node *x) {

	if(x==NULL || flag) return 0;

	if(!x->opt) {

		if(x->f) return a[x->s];

		return x->s;

	}

	ll l=cal(x->l), r=cal(x->r), ret=0;

	int opt=x->s;

	if(flag) return 0;

	if(opt=='/' && r==0) { flag=1; return 0; }

	if(opt=='+') ret=l+r;

	if(opt=='-') ret=l-r;

	if(opt=='*') ret=l*r;

	if(opt=='/') ret=l/r;

	if(abs(ret)>eps) { flag=1; return 0; }

	return ret;

}

void build(int l, int r, node *&x) {

	// if(db>1) return;

	// ++db;

	// assert(l<=r);

	if(l==r) {

		x=new node();

		x->f=b[l].f;

		x->s=b[l].s;

		return;

	}

	int p=0, c1=-1, c2=-1;

	for1(i, l, r) {

		if(!b[i].opt) continue;

		if(b[i].s=='(') ++p;

		else if(b[i].s==')') --p;

		else if(!p && (b[i].s=='+' || b[i].s=='-')) c1=i;

		else if(!p && (b[i].s=='*' || b[i].s=='/')) c2=i;

	}

	if(c1==-1) c1=c2;

	if(c1==-1) { build(l+1, r-1, x); return; }

	//puts("here"); dbg(c1);

	x=new node();

	build(l, c1-1, x->l); build(c1+1, r, x->r);

	x->opt=1;

	x->s=b[c1].s;

}

int main() {

	read(n); read(m);

	for1(i, 1, n) {

		scanf("%s", s);

		getid(s, strlen(s));

	}

	char c=getchar(); while(c=='\n'||c=='\r'||c==' ') c=getchar();

	while(c!='\n') {

		if(c>='0' && c<='9') {

			int r=0;

			while(c>='0' && c<='9') r=r*10+c-'0', c=getchar();

			b[++tot].s=r;

		}

		else if((c>='A' && c<='Z') || (c>='a' && c<='z')) {

			int len=0;

			while((c>='A' && c<='Z') || (c>='a' && c<='z')) s[len++]=c, c=getchar();

			s[len]='\0';

			b[++tot].s=getid(s, len);

			b[tot].f=1;

		}

		else if(c!='\n') {

			b[++tot].opt=1;

			b[tot].s=c;

			c=getchar();

		}

	}

	build(1, tot, root);

	while(m--) {

		for1(i, 1, n) read(a[i]);

		flag=0;

		int ans=cal(root);

		if(flag) puts("Error!");

		else printf("%d\n", ans);

	}

	return 0;

}

 

 


 

 

描述

计算器是生活中的常用计算工具,可以用来计算各种各样的代数式的值。不过它是有些缺点的,一个主要的问题是它只支持常量的运算。对于同样形式的代数式,仅仅是因为常量的不同就需要重新输入一遍。

程序员们则可以使用高级语言中的表达式求值。在Pascal/C++语言中,表达式是一个很基础的概念。表达式中可以出现变量、常量、运算符、括号,甚至各种各样的函数。

这里我们仅考虑这样的表达式:它由52个大小写英文字母、数字'0'~'9',和’(’、’)’、’+’、’-’、’*’、’/'这些符号组成。每 个运算符都只执行双目运算符的功能,即它的左右两侧都必须是可计算的量。特别的,这里使用'/'符号表示整除。而连续的英文字母组成的单词则表示变量名, 且变量名仅由字母组成。为了简化问题,表达式中的常量均为绝对值不超过10^9的自然数,且无前导0。表达式的计算方法和在源程序中是一样的,即小括号优 先级最高、而'*'、'/'运算符优先级高于'+'、‘-’运算符,同一优先级从左到右按顺序计算。

你的任务,就是对于一个给定的表达式,实现它的计算功能。我们将声明N个变量,并在表达式中引用这些变量。然后给出T组数据。每组数据都是N个变量的一组取值。你需要对每组数据计算此时表达式的返回值。

格式

输入格式

输入文件的第一行包括两个整数N, T,依次表示表达式中引用的变量的数目,以及N个变量的需要计算的取值组数。

接下来N行,每行一个由英文字母组成的字符串,依次表示每个变量名。

接下来一行,一个字符串,表示表达式的内容。

接下来T行,每行N个整数,依次表示每个变量这时的取值。

输出格式

输出文件包括T行,第i行表示N个变量取输入的第i组数值时表达式的答案。

如果在运算过程中出现整数被0除,或者运算过程的中间结果的绝对值大于10^9,输出”Error!”;否则输出一个整数,表示运算结果。运算的中间结果指从左到右按优先级顺序计算时得到的每个数值。

样例1

样例输入1[复制]

2 3

x

total

1+(total/x)

1 3

2 155

0 0

样例输出1[复制]

4

78

Error!

限制

1s

提示

20%的数据满足,表达式中没有小括号。

另外20%的数据满足,表达式中没有加法或减法运算。

另外20%的数据满足,表达式中没有乘法或除法运算。

80%的数据(包括上述在内)满足,表达式的长度不超过100。

100%的数据满足,1 <= N <= 100,1 <= T <= 10,变量名长度不超过10,表达式长度不超过100,000。变量的取值和表达式中的常量是绝对值不超过10^9的自然数。所有变量名互不相同。

 

你可能感兴趣的:(OS)