usaco5.5.3 Two Five
2017-09-18 13:54
232 查看
一 原题
TwofiveIOI 2001
In order to teach her young calvess the order of the letters in the alphabet, Bessie has come up with a game to play with them. The calves are given a 5 x 5 grid on which they can put the letters 'A'-'Y',
but the one rule is that all the letters going across the columns and down the rows must be in the order they appear in the alphabet.
There are a huge number of possible grids, so Bessie decides that they will be named by the string of letters that is given by reading across each row, going down the rows. For example, the grid:
A B C D E F G H I J K L M N O P Q R S T U V W X Y
would have the name ABCDEFGHIJKLMNOPQRSTUVWXY, which is coincidentally the first possible grid when the entire set of grids is ordered alphabetically. The second grid that meets this requirement is ABCDEFGHIJKLMNOPQRSUTVWXY,
which is formed by switching the 'T' and 'U' in the above grid.
Help the calves gain bragging rights. Given a number, M, find which string is Mth in the list of all possible grids when they are sorted alphabetically, and, given a string of letters, find out what number
the corresponding grid is in the list of all possible grids.
PROGRAM NAME: twofive
INPUT FORMAT
The first input line contains one of two letters, either an 'N' or a 'W'.If the first input line contains an 'N', the second line will contain an integer, M, that corresponds to the number of a valid grid. If the first line contains a 'W', the second line will contain a string
of 25 letters, which represents a valid grid.
OUTPUT FORMAT
If the input contained the number of a valid grid (first line 'N'), the output should contain a string of 25 letters on a line, which corresponds to the Mth grid in the sorted list of all possible grids.If the input contained a string of letters indicating a grid (first line 'W'), the output should contain a single integer on a line, which corresponds to the number of the given grid in the list of all possible
grids.
SAMPLE INPUT #1 (file twofive.in)
N 2
SAMPLE OUTPUT #1 (file twofive.out)
ABCDEFGHIJKLMNOPQRSUTVWXY
SAMPLE INPUT #2 (file twofive.in)
W
ABCDEFGHIJKLMNOPQRSUTVWXY
SAMPLE OUTPUT #2 (file twofive.out)
2
二 分析
记忆化搜索,比较难的一道题。通过前缀记数的方法完成字母和数字之间的转换。问题转换为给定前缀,求有多少个合法的摆放方法。考虑按照A-Y的顺序依次把字母填进表格,填表时需要满足3条规则:(1)所填字母的左边不能为空;(2)所填字母的上方不能为空;(3)如果字母在前缀中,则必须填在对应位置,如果字母不在前缀中,也不能占据前缀中出现的字母的位置。因为字母的位置调换会带来大量的合法摆法,所以这一题直接搜索是过不了的。标准做法里搜索状态的表示很精妙,我们用F[a][c][d][e]表示按照从A-Y的顺序摆,第一行摆a个字母,第二行摆b个字母。。。的合法摆法数量。这种状态表示的合理性依赖上述的(1)(2)两条规则。这样抽象过的状态就大大减少了搜索空间。再用记忆化搜索优化一下,速度非常快。
三 代码
运行结果:USER: Qi Shen [maxkibb3] TASK: twofive LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.000 secs, 4216 KB] Test 2: TEST OK [0.000 secs, 4216 KB] Test 3: TEST OK [0.000 secs, 4216 KB] Test 4: TEST OK [0.000 secs, 4216 KB] Test 5: TEST OK [0.000 secs, 4216 KB] Test 6: TEST OK [0.000 secs, 4216 KB] Test 7: TEST OK [0.000 secs, 4216 KB] Test 8: TEST OK [0.000 secs, 4216 KB] Test 9: TEST OK [0.000 secs, 4216 KB] Test 10: TEST OK [0.000 secs, 4216 KB] Test 11: TEST OK [0.000 secs, 4216 KB] Test 12: TEST OK [0.000 secs, 4216 KB] All tests OK.Your program ('twofive') produced all correct answers! This is your
submission #4 for this problem. [b]Congratulations!
AC代码:
/* ID:maxkibb3 LANG:C++ PROB:twofive */ #include<cstdio> #include<cstring> char Str[30]; int Appear[30]; int Table[6][6][6][6][6]; inline bool ok(int _l, int _c, int _upc) { if(_c == 5) return false; if(Str[_l * 5 + _c] != '\0') return false; if(_c + 1 > _upc) return false; return true; } int dfs(int _a, int _b, int _c, int _d, int _e) { if(Table[_a][_b][_c][_d][_e] != 0) return Table[_a][_b][_c][_d][_e]; int id = _a + _b + _c + _d + _e; if(id == 25) return Table[5][5][5][5][5] = 1; int ret = 0; if(Appear[id] != -1) { int line = Appear[id] / 5; if(line == 0) ret = dfs(_a + 1, _b, _c, _d, _e); else if(line == 1) ret = dfs(_a, _b + 1, _c, _d, _e); else if(line == 2) ret = dfs(_a, _b, _c + 1, _d, _e); else if(line == 3) ret = dfs(_a, _b, _c, _d + 1, _e); else if(line == 4) ret = dfs(_a, _b, _c, _d, _e + 1); } else { if(ok(0, _a, 5)) ret += dfs(_a + 1, _b, _c, _d, _e); if(ok(1, _b, _a)) ret += dfs(_a, _b + 1, _c, _d, _e); if(ok(2, _c, _b)) ret += dfs(_a, _b, _c + 1, _d, _e); if(ok(3, _d, _c)) ret += dfs(_a, _b, _c, _d + 1, _e); if(ok(4, _e, _d)) ret += dfs(_a, _b, _c, _d, _e + 1); } return Table[_a][_b][_c][_d][_e] = ret; } int main() { freopen("twofive.in", "r", stdin); freopen("twofive.out", "w", stdout); char c, s[30], ans_s[30] = {'\0'}; int n, ans_n = 0; scanf("%c", &c); if(c == 'W') { scanf("%s", s); memset(Appear, -1, sizeof(Appear)); for(int i = 0; i < 25; i++) { for(Str[i] = 'A'; Str[i] < s[i]; Str[i]++) { if(Appear[Str[i] - 'A'] != -1) continue; if(i % 5 != 0 && Str[i] < Str[i - 1]) continue; if(i / 5 != 0 && Str[i] < Str[i - 5]) continue; Appear[Str[i] - 'A'] = i; memset(Table, 0, sizeof(Table)); ans_n += dfs(0, 0, 0, 0, 0); Appear[Str[i] - 'A'] = -1; } Appear[Str[i] - 'A'] = i; } printf("%d\n", ++ans_n); } else { scanf("%d", &n); memset(Appear, -1, sizeof(Appear)); for(int i = 0; i < 25; i++) { for(Str[i] = 'A';; Str[i]++) { if(Appear[Str[i] - 'A'] != -1) continue; if(i % 5 != 0 && Str[i] < Str[i - 1]) continue; if(i / 5 != 0 && Str[i] < Str[i - 5]) continue; Appear[Str[i] - 'A'] = i; memset(Table, 0, sizeof(Table)); int tmp = dfs(0, 0, 0, 0, 0); if(tmp >= n) { ans_s[i] = Str[i]; break; } n -= tmp; Appear[Str[i] - 'A'] = -1; } } printf("%s\n", ans_s); } return 0; }
// better-written code
/* ID:maxkibb3 LANG:C++ PROB:twofive */ #include<cstdio> #include<cstring> char Prefix[26]; int F[6][6][6][6][6]; bool ok(int _x, int _dep) { return !Prefix[_x] || Prefix[_x] == _dep + 'A'; } int dfs(int _a, int _b, int _c, int _d, int _e, int _dep) { if(_dep == 25) return 1; int ret = 0, tmp = F[_a][_b][_c][_d][_e]; if(tmp) return tmp; if(_a < 5 && ok(_a, _dep)) ret += ac2f dfs(_a + 1, _b, _c, _d, _e, _dep + 1); if(_b < _a && ok(_b + 5, _dep)) ret += dfs(_a, _b + 1, _c, _d, _e, _dep + 1); if(_c < _b && ok(_c + 10, _dep)) ret += dfs(_a, _b, _c + 1, _d, _e, _dep + 1); if(_d < _c && ok(_d + 15, _dep)) ret += dfs(_a, _b, _c, _d + 1, _e, _dep + 1); if(_e < _d && ok(_e + 20, _dep)) ret += dfs(_a, _b, _c, _d, _e + 1, _dep + 1); return F[_a][_b][_c][_d][_e] = ret; } int main() { freopen("twofive.in", "r", stdin); freopen("twofive.out", "w", stdout); char c, s[26], ans_s[26] = {'\0'}; int n, ans_n = 0; scanf("%c", &c); if(c == 'W') { scanf("%s", s); for(int i = 0; i < 25; i++) { for(Prefix[i] = 'A'; Prefix[i] < s[i]; Prefix[i]++) { memset(F, 0, sizeof(F)); ans_n += dfs(0, 0, 0, 0, 0, 0); } } printf("%d\n", ans_n + 1); } else { scanf("%d", &n); for(int i = 0; i < 25; i++) { for(Prefix[i] = 'A';; Prefix[i]++) { memset(F, 0, sizeof(F)); int tmp = dfs(0, 0, 0, 0, 0, 0); if(tmp >= n) break; else n -= tmp; } ans_s[i] = Prefix[i]; } printf("%s\n", ans_s); } return 0; }
相关文章推荐
- USACO 5.5.3 Two Five
- 【USACO 5.5.3】Two Five
- CodeVS 1416|USACO Train 5.5.3|Two Five|二五语言|搜索
- USACO5.5.3 (twofive)
- [USACO5.5.3]Twofive
- USACO 5.5.3 Twofive 记忆式搜索+枚举
- 【BZOJ】1610: [Usaco2008 Feb]Line连线游戏(几何)
- 【BZOJ 3445】【Usaco2014 Feb】Roadblock
- 【BZOJ】1616: [Usaco2008 Mar]Cow Travelling游荡的奶牛(dp/-bfs)
- 【USACO 3.1】Contact(01子串按出现次数排序)
- bzoj 3892: [Usaco2014 Dec]Marathon 动态规划
- 【BZOJ】1631: [Usaco2007 Feb]Cow Party(dijkstra)
- USACO Milking Cows
- bzoj 1593: [Usaco2008 Feb]Hotel 旅馆 (线段树)
- 【BZOJ】1634: [Usaco2007 Jan]Protecting the Flowers 护花(贪心)
- bzoj:1703: [Usaco2007 Mar]Ranking the Cows 奶牛排名
- BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]
- usaco-2.3-zerosum-pass
- usaco1.2.1 Milking Cows
- 3942: [Usaco2015 Feb]Censoring [KMP]