第三届H-star 程序设计竞赛初赛题解

     1.剪纸片:这是一道简单的题目,假如你身边有一张纸,一把剪刀,在H-star的比赛现场,你会这么做:(1). 将这张纸剪成两片(平行于短边剪开);(2)将其中一片剪成一个圆,作为圆柱的底面;(3) 纸的另一片的一边沿着圆的周长将圆围起来,直到围成一圈,形成一个无盖的圆柱体。需要注意的是,纸片可能会有重叠部分。聪明的你机智的你喜欢思考的你这时候就开始想,一张纸片按上述方式所组成的圆柱的最大体积是多少呢?请你用编程解决这个问题。

输入

输入第一行包含一个数字t代表接下来有t组数据;
接下来的t行,输入两个数字w, h(1 ≤ w ≤ h ≤ 100),分别代表纸片的宽和高。

输出

对每一组数据输出纸片所能构成的最大圆柱体的体积v(保留小数点的后三位小数)。

样例输入

3
10 10 
10 50 
10 30

样例输出

54.247
785.398
412.095

提示

第一个测试样例,圆的半径是1.591549, 第二个测试样例,圆的半径是5, 第三个测试样例,圆的半径是3.621795.PI用acos(-1)表示

思路:假定地面半径是r,那么r必定小于等于w的1/2,这时候以w为高,那么必须满足h-2*r >= 2*pi*r,求的最大值,还有一种情况是以h-2*r为高,那么必须满足,w>=2*pi*r通过求导解得最大值,最后结果在两个最大值之间取最大值!

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
 
 
using namespace std;
const double pi = acos(-1);
 
double l,h;
int t;
 
int main(){
    cin >> t;
    while(t--){
        cin >> h >> l;
        double r = min(h/2.0,l/(2.0+2.0*pi));
        double v = pi*r*r*h;
        r = min(l/3.0,h/(2.0*pi));
        v = max(v,pi*r*r*(l-2*r));
        printf("%.3f\n",v);
    }
    return 0;
}

2.废品收集记:敲代码不是唯一的出路,但是假如H-star题目太难了,让你放弃了以后当程序员的念头,放弃身边的那个Ta,那么你就有可能去捡破烂,假如你去捡破烂,就会碰到下述问题:
在河海有n个垃圾桶,每个垃圾桶里面都有价值为m,体积为b的废品。但是你的背包体积只有V,为了赚更多钱,为了身边的Ta更幸福,你每一次捡破烂,都希望自己体积为V的背包里装的废品价值尽量多。
所以你又想起你曾经敲过的代码,你决定写一个程序解决这个问题。

输入

输入一个数字t,表示有t组数据:
每一组数据有三行:
第一行:输入两个数字n,V(n <= 1000, V <= 1000);n表示垃圾桶的数量,V表示背包的容量
第二行:输入包括n个数字,代表每个垃圾桶中废品的价值m
第三行:输入包括n个数字,代表每个垃圾桶中废品需要占用的背包的容量b

输出

输出你每次出去捡破烂背包所能装下破烂的最大价值(保证每次输出数据都在整形范围内)。

样例输入

1

5 10

1 2 3 4 5

5 4 3 2 1

样例输出

  14

 思路:简单的单重背包裸体,就是递推关系,建议看一下背包九讲里面的东西就可以了

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
 
using namespace std;
int n,t,bag;
int v[1005];
int vl[1006];
int dp[1005];
 
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&bag);
        for(int i= 0; i < n; i++)
        {
            scanf("%d",&vl[i]);
        }
        for(int i= 0; i < n; i++)
        {
            scanf("%d",&v[i]);
        }
        memset(dp,0,sizeof(dp));
        for(int i = 0;i < n;i++){
            for(int j = bag;j > 0;j--){
                if(j >= v[i]){
                    dp[j] = max(dp[j],dp[j-v[i]]+vl[i]);
                }
            }
        }
        printf("%d\n",dp[bag]);
    }
    return 0;
}

3.

3.Northcott游戏:alpha和GrayGraySmall正在玩一种Northcott游戏,可是alpha老是输,因此他怀疑这个游戏是不是有某种必胜策略,郁闷的alpha现在向你求救了,你能帮帮他么?
游戏规则是这样的:
如图所示,游戏在一个n行m列(1 ≤ n ≤ 1000且2 ≤ m ≤ 100)的棋盘上进行,每行有一个黑子(黑方)和一个白子(白方)。执黑的一方先行,每次玩家可以移动己方的任何一枚棋子到同一行的任何一个空格上,当然 这过程中不许越过该行的敌方棋子。双方轮流移动,直到某一方无法行动为止,移动最后一步的玩家获胜。alpha总是先下(黑方)。图1是某个初始局面,图二是 alpha移动一个棋子后的局面(第一行的黑子左移两步)。

输入

 输入数据有多组。每组数据第一行为两个整数n和m,由空格分开。接下来有n行,每行两个数Ti,Ji (1 ≤ Ti, Ji ≤ m)分别表示alpha和GrayGraySmall在该行棋子所处的列数。
注意:各组测试数据之间有不定数量的空行。你必须处理到文件末。

输出

  对于每组测试数据输出一行你的结果。如果当前局面下alpha有必胜策略则输出“I WIN!”,否则输出“BAD LUCK!”。

样例输入

3 6

4 5

1 2

1 2

样例输出

BAD LUCK!

 思路:这个是博弈论的简单题目,没啥要说的,反正比赛不会,原题是杭电的题,

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
 
using namespace std;
 
int n,m;
int a,b;
 
int main(){
    while(~scanf("%d%d",&n,&m)){
        int tag = 0;
        while(n--){
            scanf("%d%d",&a,&b);
            tag ^= abs(a - b) - 1;
        }
        if(tag){
            printf("I WIN!\n");
        }
        else{
            printf("BAD LUCK!\n");
        }
    }
    return 0;
}

4.我在NE304敲代码的时候吃女神送给我的糖果一个立志做程序员的人,做什么都会想到敲代码。小明的女神曾经送给他一堆糖果,但是他一直舍不得吃,最后等到了H-Star比赛,小明就把女神送给他的苹果带到了比赛现场,当作女神对他的祝福。但是问题往往就在这时候浮现在他的脑海:小明有一个癖好,吃糖果的时候,不喜欢连着吃同一种糖果,喜欢先吃一种,下一次吃另一种(小明一次只吃一颗糖果);可是小明不知道是否存在一种吃糖果的顺序使得他能把所有糖果都吃完。小明认为这是女神对他的一个考验,也是祝福,所以马上在NE304敲起了代码…

输入

 第一行有一个整数T,接下来T组数据,每组数据占2行,第一行是一个整数N(0<N<=1000000),第二行是N个数,表示N种糖果的数目Mi(0<Mi<=1000000)。

输出

对于每组数据,输出一行,包含一个"Yes"或者"No"。

样例输入

2

3

4 1 1

5

5 4 3 2 1

样例输出

No

Yes

思路:很简单的题目了,对于一种的n个糖果必须有其他种类的糖果的总和>=n-1来分开,这样就没有什么难度了,坑点就是总和会超过int。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
long long  a[1000005];
int n;
 
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n;
        long long sum = 0;
        for(int i = 0; i < n; i++)
        {
            cin >> a[i];
            sum += a[i];
        }
        int tag = 0;
        for(int i = 0; i < n; i++)
        {
            if(a[i] > sum-a[i]+1)
            {
                tag  =1;
                break;
            }
        }
        if(!tag)
        {
            cout << "Yes" << endl;
        }
        else
        {
            cout << "No" << endl;
        }
    }
    return 0;
}

 

5.Lecture:coco有一个说话特别特别快的新图论老师,因为说话太快所以coco虽然勉强能跟得上老师的课但是却没办法记好笔记,好在coco很聪明,她想到了一个方法让自己跟得上课并记笔记。
coco知道两种语言,而老师上课的时候总是用第一种语言,语言中的单词都是由英文小写字母组成,每一门语言又由几个单词组成。对每一门语言来说,所有的 单词都是相互独立的,只是拼写不同。而且,对于这些语言来说每个单词都是一一对应的,对于一门语言的一个单词来说,它都会在另一门语言中有确切的单词和确切的意思.。
coco可以卸下老师讲的每一个单词,不管是第一种语言还是第二种语言。当然,在上课期间coco写下的每一个单词都是这两种语言中最短的那个。如果单词长度一样,coco会倾向于写第一种语言。
现在给你一段老师讲课的文本,找出这节课coco会在笔记本上记录的内容。

输入

第一行包含两个整数,n 和 m( 1<= n,m <= 3000),  老师堂内容的单词数和这些语言中的单词数。
接下来的 m 行包含了这些单词.第 i 行包含两个串 ai, bi。ai 是第一门语言的单词, bi 是第二门语言的单词,这两个单词拥有相同的意思.输入保证没有相同的单词出现在两种语言中,而且每个单词在一中语言中只出现一次.
接下来的一行有 n 个空格隔开的串 c1,c2,...,cn---讲课的内容.保证每一个 Ci 串都会在集合{a1,a2,...am}中.
所有的串在输入中都不空,每一个单词都由不超过10个英文小写字母组成.

输出

输出有 n 个单词::你将会记录在笔记本中的讲课内容。单词顺序不变。

样例输入

4 3

codeforces codesecrof

contest round

letter message

codeforces contest letter contest

样例输出

codeforces round letter round

思路:这道题不难,直接模拟暴力就可以过了。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
 
using namespace std;
 
int n,m;
 
struct point
{
    char a[15];
    char b[16];
} p[1005];
char c[15];
 
int main()
{
    cin >> n >> m;
    for(int i = 0; i < m; i++)
    {
        cin >> p[i].a >> p[i].b;
    }
    while(n--)
    {
        cin >> c;
        for(int i= 0; i <m; i++)
        {
            if(strcmp(c,p[i].a) == 0 || strcmp(c,p[i].b) == 0)
            {
                if(strlen(p[i].a) > strlen(p[i].b))
                {
                    cout << p[i].b;
                }
                else
                {
                    cout << p[i].a;
                }
                if(n != 0){
                   cout << " ";
                }
            }
        }
    }
    return 0;
}

 

6.回文数:回文数是顺着读和反着读都一样的数字,给你一个数字,请你判断它是不是回文数。

输入

输入一个整数t(t在int范围内)

输出

如果这个数是回文数,则输出Yes,如果不是回文数,则输出No

样例输入

121

样例输出

Yes

提示

 思路:前道题嘛,那又要说的呢,最好用字符串表示吧,主办方数据太弱,int好像能过

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
 
using namespace std;
 
int n;
char a[15];
 
int main()
{
    scanf("%s",a);
    int tag = 0;
    int len = strlen(a);
    for(int i= 0; i <= len/2;i++){
          if(a[i] != a[len-i-1]){
            tag = 1;
            break;
          }
    }
    if(tag){
        printf("No\n");
    }else{
        printf("Yes\n");
    }
    return 0;
}

后面的题,咿咿呀呀的就不会做了呢,

你可能感兴趣的:(第三届H-star)