USACO 2015 US OPEN BRONZE 铜组 题解

USACO 2015 US OPEN BRONZE

好吧,我没什么时间了,我就干脆把标程放上去,接着解释一下就行了。

 

PROBLEM 1 MOOCRYPTION

 

众所不知的,奶牛们很喜欢玩智力游戏。John农夫最近发明了一个有趣的“找单词”游戏。 这个游戏的例子如下:

USOPEN
OOMABO
MOOMXO
PQMROM

 

作为奶牛,他们只对单词“MOO”有兴趣,这个可能会出现在找单词游戏中的任何地方,可能是水平的,可能是垂直的,也有可能是对角线的出现。上面的例子出现了6MOO

 

John农夫也是单词游戏的粉丝。 由于奶牛们不想在他们有机会试一下之前,John就把解开了,他们把游戏的内容用一个代替密码给加密了。这个代替密码将字母表里的每个字母用另外一个字母代替了。比如说,A可能对应着X B可能对应着A等等。没有哪个字母和自己对应,没有两个字母对应到同样一个字母上(否则解码时会引起歧义)。

 

不幸的是,这群傻奶牛不记得用来解码的代替密码了。 所以求求你帮他们找到一个合适的代替密码,使这个游戏中出现MOO的次数最多。

 

输入格式(moocrypt.in):

第一行包括NM 分别表示这个游戏的行与列(每个最多50)。 接下来的N行,每行包括M个字符,来表示这个游戏的一行。每个字符都是从A-Z之间的一个大写字母。

 

输出格式(moocrypt.out):

输出当游戏用合适的代替密码解码后可以出现的最多MOO的次数

 

输入样例:

 

4 6

TAMHGI

MMQVWM

QMMQSM

HBQUMQ

 

输出样例:

 

6

这个就是题目描述中的加密后的游戏。 这里MO分别用QM代替了。


【题目描述】

这一道题写一个广搜就好了,但但要注意队列的长度最好要开大一点,直接搜索行与列就可以了。

【代码】

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>

using namespace std;

int N, M;
vector<string> A;

int dr[] = {-1, -1, -1, 0, 1, 1, 1, 0};
int dc[] = {-1, 0, 1, 1, 1, 0, -1, -1};

char get(int r, int c) {
if (r < 0 || N <= r || c < 0 || M <= c) {
// we are outside the grid, return a non-letter
return '_';
}
return A[r][c];
}

int main() {
freopen("moocrypt.in", "r", stdin);
freopen("moocrypt.out", "w", stdout);

cin >> N >> M;
A.resize(N);
for (int i = 0; i < M; i++) {
cin >> A[i];
}

int best = 0;
for (char mch = 'A'; mch <= 'Z'; mch++) {
// pick a character that will be set to M
if (mch == 'M') {
continue;
}
for (char och = 'A'; och <= 'Z'; och++) {
// pick a character that will be set to O
if (och == 'O' || mch == och) {
continue;
}
int result = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
// check the first character would be M
if (get(i, j) != mch) {
continue;
}
// try all possible words starting at square (i,j)
for (int k = 0; k < 8; k++) {
// check the next two characters would be O
if (get(i + 1 * dr[k], j + 1 * dc[k]) == och &&
get(i + 2 * dr[k], j + 2 * dc[k]) == och) {
result++;
}
}
}
}
best = max(best, result);
}
}
cout << best << endl;

return 0;
}


 

PROBLEM 2 BESSIE GETS EVEN

 

FJ 和奶牛Bessie最爱闲时交换数学智力游戏。最近一次FJBessie 的数学难倒了可怜的Bessie 现在她想为FJ给他那么难的题目而复仇。

 

Bessie 给了FJ 一个表达式,(B+I)(G+O+E+S)(M),包括七个变量,B,E,S,I,G,O,M (其中O 是变量不是数字0)。对每个变量,她给了FJ一个那个变量可能被赋有最多有20个整数值的清单。 她问FJ总共有多少种不同的方式来给每个变量赋值使得表达式的最终结果为偶数。

 

输入格式:(geteven.in

 

第一行包括一个整数N,接下来的N行,每行包括一个变量以及这个变量可能的值。 每个变量会至少出现一次,最多出现20次。同一个的变量不会被列两次相同的值。每个值都会在-300300之间。

 

输出格式:(geteven.out

 

输出一个整数,表示所有FJ可以给这些变量赋值使得表达式最终的结果是偶数的可能数。

 

输入样例:

10
B 2
E 5
S 7
I 10
O 16
M 19
B 3
G 1
I 9
M 2

 

输出样例:

6

 

共有6种变脸赋值的方法:

(B,E,S,I,G,O,M) = (2, 5, 7, 10, 1, 16, 19) -> 53,244
                = (2, 5, 7, 10, 1, 16, 2 ) -> 35,496
                = (2, 5, 7, 9,  1, 16, 2 ) -> 34,510
                = (3, 5, 7, 10, 1, 16, 2 ) -> 36,482
                = (3, 5, 7, 9,  1, 16, 19) -> 53,244
                = (3, 5, 7, 9,  1, 16, 2 ) -> 35,496
 

注意(2,5,7,10,1,16,19)(3,5,7,9,1,16,19) 算两种不同的赋值方法,尽管他们得出的结果是相同的。

 

【题目分析】

这一道题有很多的方法,比如杨天诚在课上所提出的数学方法。但是最简单的方法应该是直接枚举了。将每个变量所可能的奇偶情况的各自数目存入数组中,接着枚举每个变量的奇偶即可。为什么可以这样呢?因为注意到在这里只需求方案数,而且其只用求所有偶数的可能性,用一下乘法原理,乘一乘就好了。

【代码】

#include <iostream>
#include <cstdio>

using namespace std;

int num[256][2];

bool is_even(int x) {
return x % 2 == 0;
}

int main() {
freopen("geteven.in", "r", stdin);
freopen("geteven.out", "w", stdout);

int N;
cin >> N;

for (int i = 0; i < N; i++) {
char letter;
int val;
cin >> letter >> val;

if (is_even(val)) {
num[letter][0]++;
} else {
num[letter][1]++;
}
}

int result = 0;

/* Try every possible way that the variables could be even or odd. */
for(int B = 0; B < 2; B++)
for(int E = 0; E < 2; E++)
for(int S = 0; S < 2; S++)
for(int I = 0; I < 2; I++)
for(int G = 0; G < 2; G++)
for(int O = 0; O < 2; O++)
for(int M = 0; M < 2; M++) {
if (is_even((B + E + S + S + I + E) * (G + O + E + S) * (M + O + O))) {
/* If the expression is even then add the number of variable assignments
* that have the variables odd/even.
*/
result += num['B'][B] * num['E'][E] * num['S'][S] * num['I'][I] *
num['G'][G] * num['O'][O] * num['M'][M];
}
}
cout << result << endl;

return 0;
}



PROBLEM 3 TRAPPED IN THE HAYBALES

 

FJ 收到了N个大干草捆(1 < N < 4000)然后将这些干草随意的放在放到通往养牛场的路的任意位置上。不幸的是,他忘了奶牛Bessie正在路上散步,她有可能被这些捆困住。

 

每个捆j的大小为S_j, 在某个独特的位置P_j处,这个位置是一维马路上的一点。奶牛Bessie从一个没有草堆的地方出发, 他可以自由的在这条马路上走来走去,甚至走到某一捆干草所在的位置,但她不能穿过那个点。但有个例外,如果她朝着一个方向跑D各单位的距离,她可以积攒到足够的速度冲破一个大小小于D的干草捆, 这之后,那个干草捆就永远的被消灭了。当然,这之后,她可能开拓了更多的空间,使她可以跑向其他的干草捆, 并消灭这些捆。

 

Bessie如果她最终突围了最左边或最右边的任意一个甘草捆,她就逃脱了。请计算出路上Bessie无法逃脱的起始位置的总面积。比如说,如果Bessie的起始位置是在两捆之间从1到5的位置上,而且在这中间Bessie 无法逃脱,那么她无法逃脱的面积就为4。

 

输入格式:(trapped.in

 

第一行包括数字N,接下来的N行每行表示一个干草捆,包括两个整数,分别表示这个捆的大小和位置。每个值在1 ~ 10^9 之间。

 

输出格式:(trapped.out

 

输出一个整数,表示Bessie 在这条路上无法逃脱的起始位置的面积。

 

输入样例:

5
8 1
1 4
8 8
7 15
4 20

 

输出样例:

14

 

 【题目分析】

这题有一个很简单的解法,那就是不停的算两边的干草堆是否能够突破,然后不断突破,直到破出来为止,大概是O(n)的算法,非常之简单。

【代码】

见我的三四题翻译:http://wenjianwei1.blog.163.com/blog/static/183193331201581942044330/

 


 

PROBLEM 4 PALINDROMIC PATHS

 

FJ的农场是一个N*N格子形状的一块地(2<N<18), 每个格子用一个字母表示,比如:

ABCD
BXZX
CDXB
WCBA

每天,Bessie奶牛从左上角走向右下角,她每一步可以向右或向下走。 Bessie记录着她走的过程中所产生的字符串。 她的方向感很差,所以生成出来的字符串要是回文串(从前和从后读是一样的), 因为她不记得她曾经走过的方向。

 

Bessie她可以走出的不同的回文串的个数。沿不同路径走出的相同的回文串只算一次。比如说,上面的例子中有多种不同的路径可以产生出回文串ABXZXBA,但Bessie只能走出四种不同的回文串:ABCDCBA, ABCWCBA, ABXZXBA, ABXDXBA

 

输入格式:(palpath.in

第一行包括一个整数N,剩下的N行每行包括N个在A-Z之间的字符,表示这块农场。

 

输出格式:(palpath.out

输出Bessie可能走出的不同的回文串的个数。

 

输入样例:

4
ABCD
BXZX
CDXB
WCBA

 

输出样例:

4


【题目分析】
这题就不用怎么说了,直接枚举,因为规模很小,可以直接列出从左上角和右下角所能产生的字符串(到对角线),接着做两个产生字符串的集合的交集,求总大小就可以了。

【代码】
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值