表达式求解中的模运算与深度优先搜索优化
在解决涉及多个变量的代数表达式奇偶性判断问题时,常可通过模 2 运算将复杂计算简化为二进制位分析。例如,对于表达式 (B + E + S + S + I + E)(G + O + E + S)(M + O + O),其结果是否为偶数仅取决于各变量取值的奇偶性。
由于奇偶性在加法和乘法下具有封闭性:
- 偶 + 奇 = 奇
- 偶 + 偶 = 偶
- 奇 × 奇 = 奇
- 偶 × 奇 = 偶
因此,可将原式等价化简为:(B + I)、(G + O + E + S)、M 中至少有一个为偶数,则整体结果为偶数。这使得原本需枚举 20⁷ 种组合的问题,转化为只需考虑每个变量奇偶性的 2⁷ 种情况,极大降低复杂度。
通过深度优先搜索(DFS)遍历所有奇偶组合,并结合预处理各变量奇数与偶数的出现次数,可高效统计满足条件的赋值方案总数。
#include <iostream>
#include <map>
#include <vector>
using namespace std;
long long ans;
map<char, int> oddCount, evenCount;
vector<char> vars = {'B', 'E', 'S', 'I', 'G', 'O', 'M'};
map<char, int> choice;
void dfs(int idx, long long currentWays) {
if (idx == vars.size()) {
int sum1 = choice['B'] + choice['I'];
int sum2 = choice['G'] + choice['O'] + choice['E'] + choice['S'];
int sum3 = choice['M'];
if ((sum1 % 2 == 0) || (sum2 % 2 == 0) || (sum3 % 2 == 0)) {
ans += currentWays;
}
return;
}
char var = vars[idx];
// 尝试奇数
choice[var] = 1;
dfs(idx + 1, currentWays * oddCount[var]);
// 尝试偶数
choice[var] = 0;
dfs(idx + 1, currentWays * evenCount[var]);
}
int main() {
int n;
cin >> n;
while (n--) {
char ch;
int val;
cin >> ch >> val;
if (val % 2) oddCount[ch]++;
else evenCount[ch]++;
}
dfs(0, 1);
cout << ans << endl;
return 0;
}
对于线性不定方程 $ ax + by = n $ 求非负整数解的问题,因变量范围有限(≤1000),可直接枚举 $ x $ 从 0 到 $ \lfloor n/a \rfloor $,验证 $ (n - a x) $ 是否能被 $ b $ 整除且商非负。
int main() {
int a, b, n;
cin >> a >> b >> n;
for (int x = 0; x <= n / a; ++x) {
int remainder = n - a * x;
if (remainder >= 0 && remainder % b == 0) {
int y = remainder / b;
cout << "Solution: x=" << x << ", y=" << y << endl;
return 0;
}
}
cout << "No solution" << endl;
return 0;
}
在四元表达式最小值问题中,给定四个数及三个操作符(+ 或 *),要求按顺序依次合并相邻两项,目标是使最终结果最小。由于操作顺序固定,不能交换操作符,但可枚举合并顺序。使用 DFS 枚举每一步的合并对,递归构造新数组并更新最小值。
注意:数值可能溢出,应使用 long long;零的存在可能导致乘积为零,影响剪枝策略。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
ll minResult = 1e18;
void dfs(vector<ll> nums, int opIdx) {
if (nums.size() == 1) {
minResult = min(minResult, nums[0]);
return;
}
vector<ll> nextNums;
for (int i = 0; i < nums.size(); ++i) {
for (int j = i + 1; j < nums.size(); ++j) {
nextNums.clear();
for (int k = 0; k < nums.size(); ++k) {
if (k != i && k != j) nextNums.push_back(nums[k]);
}
if (opIdx == 0) nextNums.push_back(nums[i] + nums[j]);
else if (opIdx == 1) nextNums.push_back(nums[i] * nums[j]);
dfs(nextNums, opIdx + 1);
}
}
}
int main() {
vector<ll> values(4);
for (int i = 0; i < 4; ++i) cin >> values[i];
string ops;
cin >> ops;
dfs(values, 0);
cout << minResult << endl;
return 0;
}
四平方和问题要求找到一组非负整数 $ a \leq b \leq c \leq d $ 使得 $ a^2 + b^2 + c^2 + d^2 = n $,并保证字典序最小。采用分治思想:先预处理所有 $ c^2 + d^2 $ 的组合,存入哈希表;再枚举 $ a^2 + b^2 $,检查剩余部分是否存在。
#include
#include
using namespace std;
const int MAXN = 1e4 + 5;
int C[MAXN], D[MAXN];
int main() {
int n;
cin >> n;
memset(C, -1, sizeof C);
for (int c = 0; c * c <= n; ++c) {
for (int d = c; d * d + c * c <= n; ++d) {
int sum = c * c + d * d;
if (C[sum] == -1) {
C[sum] = c;
D[sum] = d;
}
}
}
for (int a = 0; a * a <= n; ++a) {
for (int b = a; b * b + a * a <= n; ++b) {
int rem = n - a * a - b * b;
if (C[rem] != -1) {
cout << a << " " << b << " " << C[rem] << " " << D[rem] << endl;
return 0;
}
}
}
return 0;
}