题目来源:
CSUOJ 2295: Infallibly Crack Perplexing Cryptarithm
Codeforces Gym 101158E Infallibly Crack Perplexing Cryptarithm
语法分析
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
#include <sstream>
#define LL long long
#define LD long double
#define ULL unsigned long long
#define UI unsigned int
#define _for(i,j,k) for(int i=j;i<=k;i++)
#define for_(i,j,k) for(int i=j;i>=k;i--)
#define lowbit(x) (x&-x)
#define ls(x) x<<1
#define rs(x) x<<1|1
//#pragma comment(linker, "/STACK:10240000000,10240000000")
using namespace std;
const int maxn = 1e5+5;
#define Result pair<char*,int>
#define Fail make_pair((char*)NULL,0)
char ctab[8]={'+','-','*','=','(',')','0','1'};
int vis[8],ta[10],cnt,an;
map<char,int> mse;
char s[35],sb[35];
Result Q(char* p);
Result E(char* p);
Result T(char* p);
Result F(char* p);
Result N(char* p);
Result Q(char* p){ //计算等号:判断左右算式是否相等
Result left = E(p); //计算左边的算式
if(left.first == NULL || *(left.first) != '=' ) return Fail;
Result right = E(left.first + 1);
if(right.first == NULL || right.second != left.second || *(right.first) != 0) return Fail;//
return right;
}
Result E(char* p){ // 计算加减法
Result ret = T(p);//计算加减法之前先计算乘法
if(ret.first == NULL) return Fail;
while(*(ret.first)=='-'||*(ret.first)=='+'){
Result tmp = T(ret.first+1);//!注意这里是递归算乘法 ,而不是调用自身 ,-\+
if(tmp.first == NULL) return Fail;
if(*(ret.first)=='+') ret.second += tmp.second;
else ret.second -= tmp.second;
ret.first = tmp.first;
}
return ret;
}
Result T(char* p){ //计算乘法
Result ret = F(p);//计算乘法之前要先计算负号和括号
if(ret.first == NULL) return Fail;
while(*(ret.first)=='*'){
Result tmp = T(ret.first+1); //这里可以是递归调用自身
if(tmp.first == NULL) return Fail;
ret.second *= tmp.second;
ret.first = tmp.first;
}
return ret;
}
Result F(char* p){ //计算负号和括号
Result ret = Fail;
if(*p == '-'){
ret = F(p+1);
if(ret.first == NULL) return Fail;
ret.second = -ret.second;
}
else if(*p == '('){
ret = E(p+1); //括号内又是一个式子了
if(ret.first == NULL || *(ret.first)!=')') return Fail;
ret.first ++;
}
else{
ret = N(p);
}
return ret;
}
Result N(char* p){ //计算数字
if(!isdigit(*p)) return Fail; //应该是数字却不是
if(*p == '0' && isdigit(*(p+1))) return Fail; //有前置零
Result ret = make_pair(p,0);
while(isdigit(*ret.first)){
(ret.second<<=1) += (*ret.first) - '0';
ret.first++;
}
return ret;
}
void solve(){
for(int i=0;s[i];i++){
if(mse.count(s[i])){
sb[i]=ctab[ta[mse[s[i]]]];
}
else sb[i]=s[i];
}
//cout<<sb<<endl;
if(Q(sb).first != NULL ) an++;
}
void dfs(int d){
if(d==cnt){
solve();
return;
}
_for(i,0,7){
if(!vis[i]){
vis[i]=1;
ta[d]=i;
dfs(d+1);
vis[i]=0;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>s;
for(int i=0;s[i];i++) if(isalpha(s[i])&&(!mse.count(s[i]))) mse[s[i]]=cnt++;
if(cnt>8){
cout<<"0";
return 0;
}
else if(cnt==0){
if(Q(s).first != NULL) an++;
}
else{
dfs(0);
}
cout<<an;
return 0;
}