NOIP 2005 提高组 T4 等价表达式(字符串乱搞)

题意

给你好多表达式,求多少个和第一个等价。

题解

因为题目限制,只有一个变量 a a ,并且次数最高为10次,所以可以大胆猜想两个本质不同的表达式代入某个 a a 时值相同的情况非常的少(具体多少并不知道)。

所以随机random一些数,做表达式求值。

表达式求值坑非常多,主要是空格和括号的问题,打在注释里了。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cmath>
#include<ctime>
#define ll long long 
using namespace std;
const int inf = 1e9+7;
const int mod = 1e9+7;
const int LIM = 1000;
const int N = 30;
const int L = 100;
int n, tot;
string s[N];
int pri[N][L];
bool b[N];

int getPri(char c)
{
	if (c == '+' || c== '-') return 1;
	else if (c == '*') return 2;
	else if (c == '^') return 3;
}

void Initialize(int id)
{
	// 空格的锅
	// string.erase()传入参数最好放指针
	// 第一次错在string的erase,在while循环里也需要判断 i < s.size()
	// 不然当 i 指向s.end()的时候鬼知道他删掉了什么
	for (int i = 0; i < s[id].size(); i++)
		while (i < s[id].size() && (s[id][i] < '0' || s[id][i] > '9') && s[id][i] != '+' && s[id][i] != '-' && s[id][i] != '*' && s[id][i] != '^' && s[id][i] != 'a' && s[id][i] != '(' && s[id][i] != ')')
			s[id].erase(s[id].begin()+i);
	
	int now = 0;
	for (int i = 0, sz = (int)s[id].size(); i < sz; i++){
		if ((s[id][i] >= '0' && s[id][i] <= '9') || s[id][i] == 'a')
			pri[id][i] = inf;
		else if (s[id][i] == '(')
			now += 4, pri[id][i] = inf;
		else if (s[id][i] == ')')
			now -= 4, pri[id][i] = inf;
		else
			pri[id][i] = now+getPri(s[id][i]);
	}
}

int Pow(int x, int y)
{
	int ret = 1;
	while (y){
		if (y&1) ret = (ll)ret*x%mod;
		x = (ll)x*x%mod;
		y >>= 1;
	}
	return ret;
}

int Calc(int x, int y, char c)
{
	if (c == '+') return ((ll)x+y)%mod;
	else if (c == '-') return ((ll)x-y+mod)%mod;
	else if (c == '*') return (ll)x*y%mod;
	else return Pow(x, y);
}

int Solve(int id, int l, int r, int x)
{
	int pos = -1, minpri = inf;
	// 相同优先级的运算符从前往后做,即优先级最高的符号中位置最后的最后做,所以从后往前扫
	for (int i = r; i >= l; i--)
		if (pri[id][i] < minpri)
			minpri = pri[id][i], pos = i;
	if (pos == -1){
		// 在这里括号要去掉,但是之前的递归不用管括号,因为他的优先级被设置成inf,并不会被当成运算符
		while (s[id][l] == '(') l++;
		while (s[id][r] == ')') r--;
		if (s[id][l] == 'a') return x;
		int ret = 0;
		for (int i = l; i <= r; i++)
			ret = ((ret<<3)+(ret<<1)+s[id][i]-'0')%mod;
		return ret;
	}
	return Calc(Solve(id, l, pos-1, x), Solve(id, pos+1, r, x), s[id][pos]);
}

/*
void test() // test函数对调试非常的有用
{
	while (getline(cin, s[0])){
		Initialize(0);
		cout << Solve(0, 0, s[0].size()-1, 6) << endl;
	}
}
*/

int main()
{
//	test();
	srand((unsigned)time(0));
	getline(cin, s[0]); Initialize(0);
	cin >> n; getline(cin, s[1]);
	for (int i = 1; i <= n; i++)
		getline(cin, s[i]), Initialize(i);
	memset(b, 0, sizeof(b));
	tot = 0;
	while (tot <= LIM){
		int num = rand()%mod;
		int resa = Solve(0, 0, s[0].size()-1, num);
		bool fl = 1;
		for (int i = 1; i <= n; i++)
			if (!b[i] && Solve(i, 0, s[i].size()-1, num) != resa){
				fl = 0;
				b[i] = 1;	
			}
		if (!fl) tot = 0;
		else tot++;
	}
	for (int i = 1; i <= n; i++)
		if (!b[i])
			cout << (char)(i+'A'-1);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/83110253