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

给出m个数字,请你找出1到n中没有出现在这m个数字中的数字个数。

Input

多组输入,每组输入第一行n和m,接下来一行m个数字a[i]。
数据范围: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 
#include 
#include 
using namespace std;
map 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,x。
接下来输入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

我们把数字的高位到低位逐渐变大的数字叫作递增数字,形如0,12344,35799。现在给出区间L和R,请你计算L到R内递增数字的个数。因为个数比较多,将答案输出mod (1e9+7)后输出。

Input

多组输入,每组输入两个数,分别代表L和R。
数据范围:0<=L<=R<=10^100。

Output

每组输出一行,表示答案个数mod 1e9+7后的值。

Sample Input

13 24
93 111
12345 54321

Sample Output

10
2
952

=============================题解===============================

还没看

1005 发现

=============================题目===============================
Problem Description

  最近,炉石传说开放了新冒险模式——探险者协会!开放了一种新的技能:“发现”!
它的效果是提供三张卡牌(随从卡 / 法术卡),你可以获得任意一张,并丢掉另外两张。
现在你可以使用 n 次“发现”技能,当然到最后你会得到 n 张卡牌,如今已经给出每次使用技能后可以选择的三张卡的属性,问你能否获得至少 a 张随从卡以及 b 张法术卡。
2015苏州大学ACM-ICPC集训队选拔赛(1)题解_第1张图片

Input

  多组输入数据(组数<=1000)
每组输入数据的第一行是三个正整数 n,a,b,含义见上述。(1 <= n <= 1000 , 1 <= a,b <= n)
接下来 n 行,每行三个数(0或1),0代表随从卡,1代表法术卡。

Output

  对于每组数据,输出一行 YES 或者 NO 。

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 
#include 

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

有一枚金币,其左边有a个猫粮,右边有b个猫粮,每次可以从最左或者最右取一个物品,先取到金币的一方获胜。

Input

第一行一个数T,表示测试数据组数(1 <= T <= 100)
接下来T行,每行有两个整数a和b,0 <=a, b<= 1e9

Output

如果先手获胜输出“First”(引号不输出), 否则输出“Second”(引号不输出)。

Sample Input

2
0 3
1 1

Sample Output

First
Second

=============================题解===============================

博弈类的题目, 不过不是经典模型, 找下规律就能看出来了.

当其中一边没有猫粮时, 肯定是先手获胜. 然后就是跟左右和的奇偶性有关了. 看代码

#include 
#include 

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

  对于每一组数据输出一行,代表概率,四舍五入到小数点后2位。(即:用 %.2f 输出)

Sample Input

1 0
2 0

Sample Output

1.00
0.00

=============================题解===============================

讲真这个题目, 我的做法是手算, 非常的...弱. 所幸数据量太少.

看代码就清楚是怎么算的了.

#include 
#include 

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

2000年某天,猪猪第一次来到苏州大学东校区,她想到本部的理工楼101定居,所以必须经过东吴桥,由于腿部肌肉拉伤,猪猪每次只能向前跳固定的距离(设距离为x),更可怕的是由于常年不锻炼身体,猪猪的体重已经达到了100KG,所以她每跳一步,桥面会下沉一个固定的高度(设该高度为y),现在告诉你x和y的值,桥的长度以及桥初始的高度,你可以帮猪猪计算出最少需要跳多少步才能过桥吗?(注意:一旦桥面的高度小于0而且猪猪还没有到河对岸,不会游泳的猪猪将会被淹死...sad)。
2015苏州大学ACM-ICPC集训队选拔赛(1)题解_第2张图片

Input

第一行一个数T,表示测试数据组数(1 <= T <= 100)
接下来T行,每行四个整数x,y,length, hight(length表示桥的长度,hight表示桥初始的高度,x和y与题目中的含义相同), 0 < x, y, length, hight <= 1e9

Output

对于每组测试数据,输出一个整数,表示最少需要的步数。如果猪猪无法过河,则输出-1

Sample Input

3
1 1 1 1
1 1 2 1
1 1 3 1

Sample Output

1
2
-1

=============================题解===============================

简单题, 只要计算猪猪过桥需要多少步, 然后计算下降的距离, 注意, 倒数第二步完成的时候, 桥的剩余高度应该是大于等于0的, 因为此时猪猪还在桥上, 最后一步完成时, 桥的剩余高度是多少都无所谓了, 反正猪猪已经在对岸了.(由前两组测试数据观察出来的结果), 然后看代码.

#include 
#include 

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

  一个死胡同由排成一列的 n 个格子组成,编号从 1 到 n 。
实验室的“猪猪”一开始在1号格子,开始向前走,每步一格,并且每走 k 步会在当前的格子上打上记号(开始时,1号格子也有记号)。由于这是死胡同,每当“猪猪”走到最左或者最右的格子时,它会改变方向。好奇的“猪猪”在想:如果我一直走,能否把所有格子都打上记号呢?
聪明的你一定知道答案!Hint1:如果 n=6,k=2,位置变化为:1 -> 3 -> 5 -> 5 -> 3 -> 1 -> 3 -> 5 .... 显然,此时不能将所有格子打上标记。(如下图)

Input

  多组输入数据(组数<=100)
每组数据一行,包含两个正整数 n 和 k。
(1 <= n <= 100000 , 1 <= k <= 100000)

Output

  对于每组数据输出一行 YES 或者 NO 代表能否给所有格子打上标记。

Sample Input

6 2
6 3

Sample Output

NO
YES

=============================题解===============================

没做出来

1010 投票

=============================题目===============================
Problem Description

苏州大学ACM-ICPC实验室一年一度的最美猫咪的选举又到了,实验室的M位同学每人可以投一票,他们会将自己最喜欢的猫咪的名字写在纸上,最终得票数超过总票数一半的猫咪将获胜。因为某种原因,我们保证选举一定会产生一个赢家。

Input

第一行一个数T,表示测试数据组数(1 <= T <= 100)
对于每组测试数据,第一行是一个整数M,表示参加选举的同学的人数(1 <= M <= 1000)
接下来M行,每行一个字符串,表示猫咪的名字,每个字符串只包含小写字母,而且每个字符串的长度不超过10

Output

对于每组测试数据输出一行,表示获胜的猫咪的名字。

Sample Input

2
3
zhuzhu
zhuzhu
xiaoxin
2
zhuzhu
zhuzhu

Sample Output

zhuzhu
zhuzhu

=============================题解===============================

讲道理这种题直接上map容器就搞定了.

#include 
#include 
#include 
using namespace std;

map 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::iterator it = mp.begin(); it != mp.end(); it++)
        {
            if( it->second > half)
            {
                ans = it->first;
                break;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(算法)