题解 UVA1099 【Sharing Chocolate】
这道题一看
我们可以设出一个显而易见的状态:
这样空间显然会炸,我们可以发现,
为了方便计算矩形的另一条边长,我们可以预处理出
方程很好列了,枚举子集
另外希望大家不要忘了register与inline的重要性!论怎样不开O2卡进最优解。
Code:
#include <cstdio>
#include <cstring>
#include <cassert>
#define min(x, y) (x < y ? x : y)
int Sum[1 << 15], A[16], n, x, y, sum;
bool f[105][1 << 15], Visit[105][1 << 15], flag[1 << 15];
inline bool scan() {
sum = 0;
scanf("%d", &n);
if (n == 0) return false;
scanf("%d%d", &x, &y);
for (register int i(1); i <= n; ++ i) scanf("%d", A + i), sum += A[i];
memset(f, false, sizeof(f));
memset(flag, false, sizeof(flag));
memset(Visit, false, sizeof(Visit));
memset(Sum, 0, sizeof(Sum));
for (register int s(1); s < 1 << n; ++ s)
for (register int i(0); i < n; ++ i) if (s & 1 << i) Sum[s] += A[i + 1];
for (register int i(0); i < n; ++ i) flag[1 << i] = true;
return true;
}
inline bool dfs(int x, int s) {
if (Visit[x][s]) return f[x][s];
if (Visit[Sum[s] / x][s]) return f[Sum[s] / x][s];//能让搜索量减半的东西,不用每次取min,这里加一行就好了。
Visit[x][s] = true;
if (flag[s]) return f[x][s] = true;
register int y(Sum[s] / x);
for (register int s0(s - 1 & s); s0; s0 = s0 - 1 & s) {
if (!(Sum[s0] % x) && dfs(x, s0) && dfs(x, s ^ s0)) return f[x][s] = true;
if (!(Sum[s0] % y) && dfs(y, s0) && dfs(y, s ^ s0)) return f[x][s] = true;
}
return f[x][s];
}
int main() {
int kase(0);
while (scan())
printf("Case %d: ", ++ kase),
puts(!(sum % x) && sum == x * y && dfs(x, (1 << n) - 1) ? "Yes" : "No");
}