Section 1.3 中除了分类的贪心,还有另外几道题, 不过并没有把这几道题贴上tags。我感觉这几道题更像简单的暴力和搜索,大概是复习之前所学知识吧。
Prime Cryptarithm
题目给出了一个三位数×两位数的竖式:
* * * x * * ------- * * * <-- partial product 1 * * * <-- partial product 2 ------- * * * *并给出几个数字, 要求用这几个数字代替竖式中的星号,使竖式成立。
做法: 简单dfs
include <bits/stdc++.h>
using namespace std;
int a[7], ans = 0;
vector <int> digits;
int trans(int *a, int z) {
int ans = 0;
for (int i = 0; i < z; i++) ans = ans * 10 + a[i];
return ans;
}
bool ok(int n) {
while (n) {
if (find(digits.begin(), digits.end(), n % 10) == digits.end()) return 0;
n /= 10;
}
return 1;
}
void dfs(int p) {
if (p == 5) {
int w = trans(a, 3), u = trans(a + 3, 2) * w, x = trans(a + 3, 1) * w, y = trans(a + 4, 1) * w;
if (u < 10000 && x < 1000 && y < 1000 && ok(u) && ok(x) && ok(y)) {
ans++;
}
return;
}
for (int i = 0; i < digits.size(); i++) {
a[p] = digits[i];
dfs(p + 1);
}
}
int main() {
freopen("crypt1.in", "r", stdin);
freopen("crypt1.out", "w", stdout);
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
digits.push_back(x);
}
dfs(0);
printf("%d\n", ans);
}
Combination Lock
题目大意是有一个三个转盘的密码锁,每个密码锁上有N个键值,有两套标准密码,只要3个转盘上每个转盘当前的值与其中一套标准的值相差均不超过2,就能解锁,问能解锁的三个数字有多少组。
做法:看到这种状态不重复求状态数的问题立马想到了后缀自动机, 蓝儿因为转盘只有3个, 所以就没有傻傻地用后缀自动机了, 不过还是采取了后缀自动机的思想存取了三个转盘上的状态。
#include <bits/stdc++.h>
using namespace std;
const int N = 1001;
int ans = 0;
struct node {
node *pre, *go[50];
node() {
memset(go, 0, sizeof go);
}
};
node a[N], *root, *last, *cur;
void add(int w, int len) {
if (last->go[w]) last = last->go[w];
else {
if (len == 3) ans++;
node *p = cur++;
last->go[w] = p;
last = p;
}
}
int mod(int x, int m) {
if (x < 0) x += m;
return x % m;
}
int c[5], b[5], n;
void dfs(int *a, int p) {
if (p == 3) return;
node *q = last;
for (int i = -2; i <= 2; i++) {
last = q;
add(mod(a[p] + i, n), p + 1);
dfs(a, p + 1);
}
}
int main() {
freopen("combo.in", "r", stdin);
freopen("combo.out", "w", stdout);
cur = a;
root = last = cur++;
scanf("%d", &n);
for (int i = 0; i < 3; i++) scanf("%d", c + i);
for (int i = 0; i < 3; i++) scanf("%d", b + i);
dfs(c, 0);
last = root;
dfs(b, 0);
printf("%d\n", ans);
}
Wormholes
题目大意:在 FJ 的农场上有 N 个虫洞, 其中虫洞两两匹配, 进入其中一个虫洞之后会移动到与其匹配的虫洞的外面。 FJ 的奶牛 Bessie 始终在农场上朝x轴方向前进, 即 Bessie 当前坐标为(x,y)的话, 则下一时刻它会出现在(x + 1, y),FJ 并不知道虫洞如何匹配, 他现在想知道有多少种匹配方式, 能使 Bessie 从农场上某一点出发之后沿一条路径循环。
做法:dfs 以及判断当前 N 个虫洞是否存在循环。
#include <bits/stdc++.h>
#define update(a, b) (a) = (a == -1) ? (b) : x[a] < x[b] ? (a) : (b)
using namespace std;
int in[12], out[12];
int x[12], y[12];
int v[12], ans = 0;
int n;
int go[12][2];
bool loop(int n) {
int d = 0;
memset(go, 0, sizeof go);
while (1) {
if (n == -1) return 0;
if (go[n][d]) return 1;
go[n][d] = 1;
n = d ? in[n] : out[n];
d ^=1;
}
}
void dfs(int p) {
if (p == n) {
for (int i = 0; i < n; i++) {
if (loop(i)) {
ans++;
break;
}
}
return;
}
if (v[p]) dfs(p + 1);
else for (int i = p + 1; i < n; i++) {
if (v[i]) continue;
v[i] = 1;
in[p] = i;
in[i] = p;
dfs(p + 1);
v[i] = 0;
}
}
int main() {
freopen("wormhole.in", "r", stdin);
freopen("wormhole.out", "w", stdout);
memset(out, 0xff, sizeof out);
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d %d", x + i, y + i);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (y[j] ^ y[i] || x[j] <= x[i]) continue;
update(out[i], j);
}
}
dfs(0);
printf("%d\n", ans);
}
FJ 有 N 个农场, 每个农场有一个海拔值, 如果海拔最高的农场和最低的农场海拔相差超过 17 的话, FJ 就要交税, 然而他不想交税, 所以他想改造农场, 改造农场的费用为改造前后的海拔差的平方, 问他最少花多少钱改造农场能够不交税。
做法:这题由于 海拔范围很小, 所以直接暴力即可。
#include <bits/stdc++.h>
using namespace std;
int a[105];
int sq(int x) {
return x * x;
}
int get(int x) {
int ans = 0;
for (int i = 0; i < x; i++) {
ans += a[i] * sq(x - i);
}
for (int i = x + 17; i <= 100; i++) {
ans += a[i] * sq(x + 17 - i);
}
return ans;
}
int main() {
freopen("skidesign.in", "r", stdin);
freopen("skidesign.out", "w", stdout);
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
a[x]++;
}
int ans = get(0);
for (int i = 1; i <= 100; i++) ans = min(ans, get(i));
printf("%d\n", ans);
}