2015苏州大学ACM-ICPC集训队选拔赛(1)题解
很惭愧, 一把年纪了, 连人家的选拔赛都不能AK. 写写题解, 继续成长. 都是很基本的题目, 没有用到太多算法.
1001 签到题
=============================题目===============================
经常有人问我,ACM是什么,有什么意义。
我回答,大概是一个逼格很高的比赛吧。
ACM国际大学生程序设计竞赛(英文全称:ACM International Collegiate Programming Contest(ACM-ICPC或ICPC)是由国际计算机学会(ACM)主办的,一项旨在展示大学生创新能力、团队精神和在压力下编写程序、分析和解决问题能力的年度竞赛。经过近30多年的发展,ACM国际大学生程序设计竞赛已经发展成为最具影响力的大学生计算机竞赛。赛事目前由IBM公司赞助。
-来自百度百科
而如今面临退役,一切都快要结束的时候,却发现自己已经逐渐习惯了这种氛围,ACM这一路走来,其中艰辛也只有自己知道,有过快乐和失望,也有期待和迷茫。从一开始奢望ACM带给我什么,到最后走的时候却发现自己更喜欢的是这过程。
我记得当年我做校赛的第一题,其中就有一句ACM就像是一个游戏,如今看来,似乎也是。在ACMer心里,ACM是一场游戏,没有爱过的人,不会懂。
如今将此题献给你们,希望未来的路上你们可以风雨无阻,努力去追寻自己喜欢的事物。所谓梦想,不是一开始的勇不可当,而是永不停息的疯狂。
本题作为签到题,无输入,请输出题目描述中ACM出现的次数,以换行结束。
=============================题解===============================
这个题不用讲吧, Ctrl + F, 然后慢慢数. 一共是12个
1002 丢失的数字
=============================题目===============================
Problem Description
Input
数据范围:1<=n,m<=100000,-1e9<=a[i]<=1e9。
Output
Sample Input
5 3 1 3 4 4 6 1 3 8 3 11 12
Sample Output
2 2
=============================题解===============================
简单题, 首先一开始的话, 区间大小是n, 然后一个一个排除, 如果x是大于1且小于等于n的数 且没有出现过, 那就减一.
#include <iostream> #include <cstdio> #include <map> using namespace std; map<int, bool> mp; int main() { int n, m; while(~scanf("%d%d", &n, &m)) { mp.clear(); int cnt = n; while(m--) { int x; scanf("%d", &x); if(x>=1 && x<=n && mp.find(x) == mp.end()) { mp[x] = true; cnt--; } } printf("%d\n", cnt); } return 0; }
1003 投放炸弹
=============================题目===============================
Problem Description
曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。-来自百度百科
现在给出一个n*m的平面图,'.'表示无人区,'*'表示居民区。炸弹只能投放在无人区,炸弹能炸毁曼哈顿距离小于等于x的所有居民区,现在你要来投放这个炸弹,请输出炸弹最多能炸毁的居民区个数。
Input
接下来输入n行,每行m个字符,字符只有'.'和'*'。
数据范围:1<=n,m<=200,1<=x<=1e9
Output
Sample Input
4 5 1 ..*.. **.** ..*.. ..... 2 3 4 *** ***
Sample Output
4 0
=============================题解===============================
对于每个无人区, 求它的曼哈顿距离内居民区的个数, 然后求最大值.
因为宝宝的求居民区的个数算法太差, 超时中....
1004 防AK的数字
=============================题目===============================
Problem Description
Input
数据范围:0<=L<=R<=10^100。
Output
Sample Input
13 24 93 111 12345 54321
Sample Output
10 2 952
=============================题解===============================
还没看
1005 发现
=============================题目===============================
Problem Description
它的效果是提供三张卡牌(随从卡 / 法术卡),你可以获得任意一张,并丢掉另外两张。
现在你可以使用 n 次“发现”技能,当然到最后你会得到 n 张卡牌,如今已经给出每次使用技能后可以选择的三张卡的属性,问你能否获得至少 a 张随从卡以及 b 张法术卡。
Input
每组输入数据的第一行是三个正整数 n,a,b,含义见上述。(1 <= n <= 1000 , 1 <= a,b <= n)
接下来 n 行,每行三个数(0或1),0代表随从卡,1代表法术卡。
Output
Sample Input
1 1 0 1 1 1 3 1 2 0 1 1 0 0 0 1 1 1
Sample Output
NO YES Hint:对于第一组样例,n=1,a=1,b=0,使用1次“发现”技能,至少获得1张随从卡。由于提供的3张都是法术卡(3个1),所以不能达到要求。 对于第二组样例,n=3,a=1,b=2,使用3次“发现”技能,至少获得1张随从卡,2张法术卡。那么只要在第一次和第三次选法术卡,第二次选随从卡即可。
=============================题解===============================
简单题, 把每次抽卡分成两种情况, 第一种, 三张卡一样, 都是法术卡或者都是随从卡, 第二种情况, 三张卡不一样, 有法术卡也有随从卡.
第一种情况抽到的卡是固定的, 因为三张卡都是一样的, 所以没得选, 第二种情况的卡不一样, 所以可以选.
所以只要判断抽到的固定的卡加上可选的卡是否能满足要求即可.
#include <iostream> #include <cstdio> using namespace std; int bigger(int a, int b) { if(a < b)return 0; return a-b; } int main() { int n, a, b; int cards[5]; while(~scanf("%d%d%d", &n, &a, &b)) { int ca, cb, cc; ca = cb = cc = 0; for(int i = 0; i < n; i++) { scanf("%d%d%d", &cards[1], &cards[2], &cards[3]); if(cards[1] == cards[2] && cards[2] == cards[3]) { if(cards[1])cb++; else ca++; }else{ cc++; } } string ans; ans = "NO"; if((ca >= a && cb>=b) || (ca < a && cb >= b && ca + cc >= a) || (ca >= a && cb < b && cb + cc >= b) || (bigger(b, cb) + bigger(a, ca) <= cc)) { ans = "YES"; } cout << ans << endl; } return 0; }
1006 取金币
=============================题目===============================
Problem Description
Input
接下来T行,每行有两个整数a和b,0 <=a, b<= 1e9
Output
Sample Input
2 0 3 1 1
Sample Output
First Second
=============================题解===============================
博弈类的题目, 不过不是经典模型, 找下规律就能看出来了.
当其中一边没有猫粮时, 肯定是先手获胜. 然后就是跟左右和的奇偶性有关了. 看代码
#include <iostream> #include <cstdio> using namespace std; int main() { int t; scanf("%d", &t); while(t--) { int left, right; scanf("%d%d", &left, &right); if(left == 0 || right == 0) { printf("First\n"); continue; } printf("%s\n", (left + right) % 2 == 0 ? "Second" : "First"); } return 0; }
1007 连通图
=============================题目===============================
Problem Description
(1)完全图:n 个点的图中任意两个点之间都有一条边相连,所以有 n*(n-1)/2 条边。(没有图)
(2)连通图:图中任意两个点之间都有路径,所以至少得有 (n-1) 条边。(没有图)
现在给出一个 n 个点的完全图,要从其中选择 k 条不同的边,问这 n 个点与选择的边能构成连通图的概率?
Input
每组数据一行,有两个数 n 和 k。
数据范围:1 <= n <= 4,0 <= k <= n*(n-1)/2 。
Output
Sample Input
1 0 2 0
Sample Output
1.00 0.00
=============================题解===============================
讲真这个题目, 我的做法是手算, 非常的...弱. 所幸数据量太少.
看代码就清楚是怎么算的了.
#include <iostream> #include <cstdio> using namespace std; int main() { int n, k; while(~scanf("%d%d", &n, &k)) { if(1 == n) { printf("1.00\n"); continue; } if(k < n-1) { printf("0.00\n"); continue; } if(2 == n || 3 == n || k>=4){ printf("1.00\n"); continue; } if(k == 3){ printf("0.80\n"); } } return 0; }
1008 猪猪过河
=============================题目===============================
Problem Description
Input
接下来T行,每行四个整数x,y,length, hight(length表示桥的长度,hight表示桥初始的高度,x和y与题目中的含义相同), 0 < x, y, length, hight <= 1e9
Output
Sample Input
3 1 1 1 1 1 1 2 1 1 1 3 1
Sample Output
1 2 -1
=============================题解===============================
简单题, 只要计算猪猪过桥需要多少步, 然后计算下降的距离, 注意, 倒数第二步完成的时候, 桥的剩余高度应该是大于等于0的, 因为此时猪猪还在桥上, 最后一步完成时, 桥的剩余高度是多少都无所谓了, 反正猪猪已经在对岸了.(由前两组测试数据观察出来的结果), 然后看代码.
#include <iostream> #include <cstdio> using namespace std; int main() { int t; scanf("%d", &t); while(t--) { int x, y, len, height; scanf("%d%d%d%d", &x, &y, &len, &height); int steps = len / x; if(len % x != 0) steps++; int ans; ans = steps; if(height - (steps - 1) * y < 0) { ans = -1; } printf("%d\n", ans); } return 0; }
1009 死胡同
=============================题目===============================
Problem Description
实验室的“猪猪”一开始在1号格子,开始向前走,每步一格,并且每走 k 步会在当前的格子上打上记号(开始时,1号格子也有记号)。由于这是死胡同,每当“猪猪”走到最左或者最右的格子时,它会改变方向。好奇的“猪猪”在想:如果我一直走,能否把所有格子都打上记号呢?
聪明的你一定知道答案!Hint1:如果 n=6,k=2,位置变化为:1 -> 3 -> 5 -> 5 -> 3 -> 1 -> 3 -> 5 .... 显然,此时不能将所有格子打上标记。(如下图)
Input
每组数据一行,包含两个正整数 n 和 k。
(1 <= n <= 100000 , 1 <= k <= 100000)
Output
Sample Input
6 2 6 3
Sample Output
NO YES
=============================题解===============================
没做出来
1010 投票
=============================题目===============================
Problem Description
Input
对于每组测试数据,第一行是一个整数M,表示参加选举的同学的人数(1 <= M <= 1000)
接下来M行,每行一个字符串,表示猫咪的名字,每个字符串只包含小写字母,而且每个字符串的长度不超过10
Output
Sample Input
2 3 zhuzhu zhuzhu xiaoxin 2 zhuzhu zhuzhu
Sample Output
zhuzhu zhuzhu
=============================题解===============================
讲道理这种题直接上map容器就搞定了.
#include <iostream> #include <cstdio> #include <map> using namespace std; map<string, int> mp; int main() { int t; char buf[12]; scanf("%d", &t); while(t--) { int m; mp.clear(); scanf("%d", &m); for(int i = 0; i < m; i++) { scanf("%s", buf); if(mp.find(buf) == mp.end()) { mp[buf] = 1; }else{ mp[buf]++; } } int half = m*1.0 / 2; string ans; for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) { if( it->second > half) { ans = it->first; break; } } cout << ans << endl; } return 0; }