T1 字符串编辑
问题描述: 为了对一些资料进行保密,奶牛们要对某些文章进行编辑。编辑的方法很奇特:要把原有文章 的某些词句按照某些规则用另一些词句代替。规则的形式如下:原串 新串,表示把原串替换成 新串。假设有n 条规则,第 i 规则的原串和新串分别为Mi 和Ni,则编辑按如下过程进行:开始 编辑时,先使用第一条规则,把文章中出现的第一个M1 替换成N1,如果替换后的新文章还存在 M1,则如上处理,直到文章不存在M1 为止;然后用同样的方法使用第2,第3,……,第n 条 规则进行替换,直到所有的规则都用完为止。 注意: 1、每次都要从文章开头开始找要替换的词句 2、一条规则一旦使用完后,将不能再使用 3、每一篇文章都是可编辑的 如有四条规则: 1. ban→bab 2. baba→be 3. ana→any 4. ba b→hind the g 要编辑的文章为“banana boat”,则编辑的过程如下: 编辑顺序 编辑前的文章 编辑后的文章 使用的规则 1 banana boat babana boat 1 2 babana boat bababa boat 1 3 bababa boat beba boat 2 4 beba boat behind the goat 4 编辑后的文章为“behind the goat”。请编写一程序,帮助组委会对给定的文章进行编辑。 输入格式: 数据存放在当前目录下的文本文件“editing.in”中。 文件共有 2n+2 行。文件的第一行是一个整数n (1<=n<=10),表示规则的数目;接下来第2i 行及第2i+1 行分别表示Mi 和Ni(1<=i<=n),其长度均不超过80 个字符,且Mi 不为空串;最 后一行是要编辑的文章,长度不超过80 个字符。行末没有空格。 输出格式: 答案输出到当前目录下的文本文件“editing.out”中。 文件只有一行,表示编辑后的文章(长度不超过80 个字符)。行末也应该没有空格。 样例1 输入: 样例1 输出: 4 behind the goat ban bab baba be ana any ba b hind the g banana boat 样例2 输入: 样例2 输出: 1 shoe or shop t sh toe or top
思路:有点恶心的模拟,核心部分在于字符串替换是主串后部分的挪动
考试得分:40 pts
改后得分:80 pts
改后代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n, strl; 5 char Mi[20][1000], Ni[20][1000], para[1000]; 6 7 int init() { 8 int pos; 9 char c; 10 scanf("%d\n", &n); 11 for(int i = 1; i <= n; i++) { 12 gets(Mi[i]+1); 13 gets(Ni[i]+1); 14 } 15 gets(para+1); 16 strl = strlen(para+1); 17 return 0; 18 } 19 20 void change(int curr, int posc) { 21 int strla = strlen(Mi[curr]+1), strlb = strlen(Ni[curr]+1); 22 if(strla > strlb) { 23 for(int i = posc+strlb; i <= strl; i++) { 24 para[i] = para[i+strla-strlb]; 25 } 26 } 27 if(strla < strlb) { 28 for(int i = strl; i >= posc+strla-1; i--) { 29 para[i+strlb-strla] = para[i]; 30 } 31 } 32 for(int i = posc; i <= posc+strlb-1; i++) { 33 para[i] = Ni[curr][i-posc+1]; 34 } 35 strl = strlen(para+1); 36 return ; 37 } 38 39 int solve() { 40 int tag = 0; 41 for(int i = 1; i <= n; i++) { 42 int strlu = strlen(Mi[i]+1); 43 for(int j = 1; j <= strl; j++) { 44 for(int k = 1; k <= strlu; k++) { 45 if(Mi[i][k] != para[j+k-1]) { 46 tag = 1; 47 break; 48 } 49 } 50 if(tag == 0) { 51 change(i, j); 52 } 53 tag = 0; 54 } 55 } 56 for(int i = 1; i <= strl; i++) { 57 printf("%c", para[i]); 58 } 59 return 0; 60 } 61 62 int main() { 63 freopen("editing.in", "r", stdin); 64 freopen("editing.out", "w", stdout); 65 init(); 66 solve(); 67 return 0; 68 }
Tips:题目的描述没有非常清晰,根据$data1$与$data2$的答案来看,在规则$2$完全使用之后如果主串还出现了规则$1$可以进行编辑的内容,则应该继续使用规则$1$进行编辑,但是题目并没有说清楚
T2 产品加工
问题描述: 众所周知,一个产品的生产可能要经历好几道工序,OHOW 工厂生产的产品也是如此。工厂首 先将原料加工,得到最初产品A,接着将产品A 加工成次成品B,最后次成品B 加工成成品C。各级 产品的生产由不同的生产流水线完成。可是工厂的经理SZ 先生遇到了点麻烦,由于每种产品可能 有多条流水线生产,使得生产出来的产品相当凌乱,SZ 先生为了提高生产的效率,决定调换一些 产品的位置(每次只能两两调换),将相同产品放在一起,并且所有的产品都摆成一条直线。比如 最初的产品序列为:ABACB,那么SZ 先生希望得到的序列为AABBC。 注意:由于产品的特殊性,SZ 先生决定让产品最终的摆放顺序为A、B、C 由于工厂生产出的产品可能很多,为了节省人力、物力和时间,SZ 先生希望移动产品的次数 最少,为此,他找到了他的朋友xx,希望xx 能借助计算机帮他解决这一难题。TZ 由于正在看越策 越开心,他想请聪明的你来帮他解决这个问题,你能做到吗? 输入数据 第一行是序列的长度N (1<=N<=1000000),随后一行为N 个产品的编号(产品由A、B、C 表示), 第二行无空格。 输出数据 输出数据仅一行,为调换产品的最少次数。 样例输入 9 BBACCCBCA 样例输出 4
思路:本题其实是一道数学题,我们知道整个序列在排序之后可以分为A,B,C共3区域
所以我们统计错位的字母数量(如A字母在B区域的数量,B字母在A区域的数量……)
我们记A字母在B区域为AB,于是有AB,BA,AC,CA,BC,CB六种情况
显然,AB与BA,AC与CA,BC与CB是可以抵消的,每抵消一对$ans+1$
抵消之后必然是A,B,C三者的错位情况,每抵消一对(三个)$ans+2$
这个思路的正确性在于,将每个字母移到对应的正确区域内一定是最优的
考试得分:0 pts
改后得分:100 pts
改后代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n, na, nb, nc, ab, ba, ca, ac, bc, cb, ans, use; 5 char prod[1000005]; 6 7 int init() { 8 scanf("%d\n", &n); 9 for(int i = 1; i <= n; i++) { 10 scanf("%c", &prod[i]); 11 if(prod[i] == 'A') na++; 12 else if(prod[i] == 'B') nb++; 13 else nc++; 14 } 15 return 0; 16 } 17 18 int solve() { 19 for(int i = 1; i <= na; i++) { 20 if(prod[i] == 'B') ab++; 21 else if(prod[i] == 'C') ac++; 22 } 23 for(int i = na+1; i <= na+nb; i++) { 24 if(prod[i] == 'A') ba++; 25 else if(prod[i] == 'C') bc++; 26 } 27 for(int i = na+nb+1; i <= n; i++) { 28 if(prod[i] == 'A') ca++; 29 else if(prod[i] == 'B') cb++; 30 } 31 // printf("na:%d nb:%d nc:%d ab:%d ba:%d ac:%d ca:%d bc:%d cb:%d\n", na, nb, nc, ab, ba, ac, ca, bc, cb); 32 use = min(ab, ba), ans += use, ab -= use, ba -= use; 33 use = min(ac, ca), ans += use, ac -= use, ca -= use; 34 use = min(bc, cb), ans += use, bc -= use, cb -= use; 35 // printf("na:%d nb:%d nc:%d ab:%d ba:%d ac:%d ca:%d bc:%d cb:%d\n", na, nb, nc, ab, ba, ac, ca, bc, cb); 36 ans += ab * 2; 37 ans += ba * 2; 38 printf("%d", ans); 39 return 0; 40 } 41 42 int main() { 43 freopen("process.in", "r", stdin); 44 freopen("process.out", "w", stdout); 45 init(); 46 solve(); 47 return 0; 48 }
Tips:由于数据问题测试分数只有40 pts,但是实际上这个代码是能够拿满分的
T3 迷宫
问题描述: 小希非常喜欢玩迷宫游戏,现在她自己设计了一个迷宫游戏。在她设计的迷宫中,首先她认为 所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A 和B,那么既可以通过它从 房间A 走到房间B,也可以通过它从房间B 走到房间A,为了提高难度,小希希望任意两个房间有 且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设 计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法 从5 到达8。 数据输入: 输入包含多组数据,每组数据是一个以0 0 结尾的整数对列表,表示了一条通道连接的两个房 间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。 整个文件以两个-1 结尾。 数据输出: 对于输入的每一组数据,输出仅包括一行。如果该迷宫符合小希的思路,那么输出"1",否则 输出"0"。 输入输出样例: Migong.in 6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1 Migong.out 1 1 0
思路:并查集+判断
考试得分:60 pts
改后得分:80 pts
改后代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int fa[100005], rmb[100005]; 5 6 void start(int x) { 7 for(int i = 1; i <= x; i++) fa[i] = i; 8 } 9 10 int find(int x) { 11 if(x != fa[x]) fa[x] = find(fa[x]); 12 return fa[x]; 13 } 14 15 void amal(int x, int y) { 16 x = find(x); 17 y = find(y); 18 fa[y] = x; 19 } 20 21 bool judge(int x, int y) { 22 x = find(x); 23 y = find(y); 24 return x == y; 25 } 26 27 int solve() { 28 int a, b, tag = 0, same; 29 scanf("%d%d", &a, &b); 30 while(a != -1 && b != -1) { 31 start(100001); 32 memset(rmb, 0, sizeof(rmb)); 33 while(a != 0 && b != 0 && a!= -1 && b != -1) { 34 rmb[a] = 1; 35 rmb[b] = 1; 36 if(judge(a, b) == true) { 37 tag = 1; 38 } 39 amal(a, b); 40 scanf("%d%d", &a, &b); 41 }/* 42 for(int i = 1; i <= 100001; i++) { 43 if(rmb[i] == 1) { 44 same = find(i); 45 break; 46 } 47 } 48 for(int i = 1; i <= 100001; i++) { 49 if(rmb[i] == 1 && find(i) != same) { 50 tag = 0; 51 break; 52 } 53 }*/ 54 if(tag == 1) { 55 tag = 0; 56 printf("0\n"); 57 scanf("%d%d", &a, &b); 58 continue; 59 } 60 tag = 0; 61 printf("1\n"); 62 scanf("%d%d", &a, &b); 63 } 64 return 0; 65 } 66 67 int main() { 68 freopen("migong.in", "r", stdin); 69 freopen("migong.out", "w", stdout); 70 solve(); 71 return 0; 72 }
Tips:到现在还没有搞明白怎么加上最后这个判断
T4 牛棚安排
【问题描述】 Farmer John的N(1<=N<=1000)头奶牛分别居住在农场所拥有的B(1<=B<=20)个牛棚的某一个 里。有些奶牛很喜欢她们当前住的牛棚,而另一些则讨厌再在它们现在所在的牛棚呆下去。 FJ在忍受了若干次奶牛的抱怨后,决定为所有奶牛重新安排牛棚,使最不满的那头奶牛与最高 兴的奶牛的心情差异最小,即使这会让所有奶牛都更加郁闷。 每头奶牛都把她对各个牛棚的好感度从高到低排序后告诉了FJ 。当然,如果一头奶牛被安排到 的牛棚在她给出的列表中越靠后,她就会越郁闷。你可以认为奶牛的郁闷指数是她被分配到的牛棚 在列表中的位置。奶牛们是斤斤计较的,她们无法容忍别的奶牛在自己喜欢的牛棚里快乐地生活, 而自己却呆在一个自己不喜欢的牛棚里。每个牛棚都只能容纳一定数量的奶牛。FJ希望在每个牛棚 都没有超出容量限制的前提下,使最郁闷和最高兴的奶牛的郁闷指数的跨度最小。 FJ请你帮他写个程序,来计算这个最小的郁闷指数跨度到底是多少。 【输入】 第1行: 包含2个用空格隔开的整数N和B,分别表示牛和牛棚的数量 第2..N+1行: 每行包含B个用空格隔开的整数,刚好完全包含1..B的整数。第i+1行的第一个整 数,表示奶牛i最喜欢的牛棚编号。第二个整数表示奶牛i的列表中排在第二位,也就是她第二喜欢 的牛棚。依此类推。 第N+2行: 包含B个用空格隔开的整数,第i个整数表示牛棚i最多能容纳的奶牛的数目。所有牛 棚能容纳奶牛头数的和至少是N 。 【输出】 第1行: 输出一个整数,表示所有奶牛中最高兴与最郁闷的牛的郁闷指数跨度 【输入输出样例】 stead.in stead.out 6 4 2 1 2 3 4 2 3 1 4 4 2 3 1 3 1 2 4 1 3 4 2 1 4 2 3 2 1 3 2 【样例说明】 每头奶牛都能被安排进她的第一或第二喜欢的牛棚。下面给出一种合理的分配方案:奶牛1和 奶牛5住入牛棚1,牛棚2 由奶牛2独占,奶牛4住进牛棚3,剩下的奶牛3和奶牛6安排到牛棚4。
思路:听老师说是二分图匹配,但是我不会做,考场上写了个爆搜,想加记忆化发现没法加
考场得分:10 pts
改后得分:NaN
改后代码:NULL