【NOIP2005提高组T4】等价表达式+模拟+栈

测试地址:等价表达式

做法:这个题目我首先想到的方法是,展开表达式,存储未知数a的各个次幂的系数,展开每个表达式后再进行对比。但这样子很难处理,于是就想到把一些较大的质数代入表达式求解,然后比较,多代入几个质数,如果结果都相同,那么两个表达式就基本上等价了。至于表达式的计算,用栈的方法模拟即可。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <stack>
#define mod 100000007
using namespace std;
int n,p[6]={0,1187,1291,1523,1759,1933}; //要代入的大质数
int len,pos[210],pi;
long long ans[6],val[6];
char s[210],a[210];

void read() //读入表达式,并手动把其中的空格去掉,以便后面的操作
{
  gets(s);
  int slen=strlen(s);
  len=0;
  for(int i=0;i<slen;i++)
    if (s[i]!=' ') a[++len]=s[i];
}

long long power(long long x,int y) //快速幂求x^y(不用应该也可以...一开始没看到幂指数≤10这个条件)
{
  long long s=1,tmp=x;
  while(y!=0)
  {
    if (y&1) s=(s*tmp)%mod;
    tmp=(tmp*tmp)%mod;y>>=1;
  }
  return s%mod;
}

long long number(int l,int r) //计算字符串中[l,r]一段代表的数字
{
  long long s=0;
  for(int i=l;i<=r;i++)
    s=(s*10+a[i]-'0')%mod;
  return s%mod;
}

long long work(int l,int r) //求表达式的值
{
  int i;
  for(i=r;i>=l;i--)
  {
    if (a[i]==')') i=pos[i];
	else if (a[i]=='+'||a[i]=='-') break;
  }
  if (i>=l)
  {
    long long x,y;
	x=(work(l,i-1)+mod)%mod;
	y=(work(i+1,r)+mod)%mod;
	if (a[i]=='+') return (x+y)%mod;
	else return (x-y+mod)%mod;
  }
  for(i=r;i>=l;i--)
  {
    if (a[i]==')') i=pos[i];
	else if (a[i]=='*') break;
  }
  if (i>=l)
  {
    long long x,y;
	x=(work(l,i-1)+mod)%mod;
	y=(work(i+1,r)+mod)%mod;
	return (x*y)%mod;
  }
  for(i=r;i>=l;i--)
  {
    if (a[i]==')') i=pos[i];
	else if (a[i]=='^') break;
  }
  if (i>=l)
  {
    long long x,y;
	x=(work(l,i-1)+mod)%mod;
	y=(work(i+1,r)+mod)%mod;
	return power(x,y)%mod;
  }
  if (a[r]==')') return work(l+1,r-1);
  if (a[r]=='a') return p[pi];
  return number(l,r);
}

void calc(bool mode)
{
  stack<int> b;
  for(int i=len;i>=1;i--)
  {
    if (a[i]==')') b.push(i);
	if (a[i]=='(')
	{
	  pos[b.top()]=i;
	  b.pop();
	}
  }
  for(pi=1;pi<=5;pi++)
  {
    long long value=(work(1,len)+mod)%mod;
	if (!mode) ans[pi]=value;
	else val[pi]=value;
  }
}

int main()
{
  read();
  calc(0);
  
  scanf("%d",&n);getchar();
  for(int i=0;i<n;i++)
  {
    read();
	calc(1);
	int j;
	for(j=1;j<=5;j++)
	  if (val[j]!=ans[j]) break;
	if (j>5) printf("%c",'A'+i);
  }
  
  return 0;
}


posted @ 2016-10-23 20:00  Maxwei_wzj  阅读(319)  评论(0编辑  收藏  举报