USACO Section 1.3 Problems rest

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


Ski Course Design


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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值