1. 程式人生 > >NOIP 2005 提高組 T4 等價表示式(字串亂搞)

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; }