湖南中医药大学2017年集训队第二场选拔赛

59 篇文章 0 订阅

Problem A: 最小公倍数

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 3201   Solved: 785
[ Submit][ Status][ Web Board]

Description

求两个数的最小公倍数LCM(Least Common Multiple)

Input

每行包含两个数a,b

当a和b都等于0时表示输入结束,这组数据不用输出

Output

每行包含一个正整数:a和b的最小公倍数

Sample Input

4 6
3 5
0 0

Sample Output

12
15

【分析】

辗转相除法
【代码】
#include<stdio.h>
int main()
{
    long long a,b;
    long long t;
    long long x,y;
    while(~scanf("%lld%lld",&a,&b))
    {
        if(a==0&&b==0) break;
        x=a;
        y=b;
        while(b!=0)
        {
            t=a%b;
            a=b;
            b=t;
        }
        long long m=x*y/a;
        printf("%lld\n",m);
    }
}

Problem B: 又是比智力

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 1230   Solved: 219
[ Submit][ Status][ Web Board]

Description

松哥上了数学课之后,觉得自己智力实在有所不足,所以他决定找人辩论,以提高自己的智力,已知松哥目前的智力是m,他决定和n个人辩论,如果他对手的智力低于他,松哥的智力能够提升2,否则只能提升1,假设松哥能够取得所有的胜利,请问他完成n场辩论后能够得到的最高智力是多少?

Input

多组测试数据.
每组测试数据的第一行包含两个正整数m,n.(m<=100,n<=10^5)
第二行为n个不大于100的整数,代表与他辩论人的智力.

Output

对于每组测试数据,他完成n场辩论后,能取得的最大的智力.

Sample Input

91 5
88 90 92 94 98

Sample Output

101

【分析】

基础贪心,先对所有人的智商进行排序,排序后从最低的开始比赛,因为显然先提升自己的智商对自己更有利,当剩下的人都比自己智商高的时候,就考虑跟智商最高的人去比一场赛使自己的智商+1然后继续跟剩下的人里智商最低的比....加个小优化,数据里说其他人的智商最多只有100,所以当自己的智商超过100的时候剩下的人就不需要比了肯定是能获胜的...当然这个优化没什么意义...
【代码】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
int a[100000];
using namespace std;
int main()
{
    int m,n;
    while(~scanf("%d %d",&m,&n))
    {
        int i;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a,a+n);
        int x=0;
        for(i=0;i<n;i++)
        {
            if(m>a[i])
                m+=2;
            else
            {
                m+=1;
                a[n-1]=0;
                sort(a,a+n);
            }
            if(m>100)
            {
                x=1;
                break;
            }
        }
        if(x==1)
            m+=(n-1-i)*2;
        printf("%d\n",m);
    }
    return 0;
}


Problem C: 01字串

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 88   Solved: 71
[ Submit][ Status][ Web Board]

Description

对于长度为5位的一个01串,每一位都可能是0或1,一共有32种可能。它们的前几个是: 00000 00001 00010 00011 00100 请按从小到大的顺序输出这32种01串。

Input

 本试题没有输入。

Output

 输出32行,按从小到大的顺序每行一个长度为5的01串。

Sample Input

Sample Output

00000
00001
00010
00011
< 以下部分省略>

【分析】

一种解法是打表...然而这种不存在超时情况的题目没有必要打表....
乍一眼就看得出来这个其实只是二进制.....所以从小到大输出也就是从0的二进制输出到(2^5)-1=31的二进制
【代码】
#include <iostream>    
#include <cstdio>
#include <math.h>
using namespace std;    
      
void write(int x)    
{    
    for(int i=4;i>=0;i--)    
    {    
        if(x&(1<<i))    
            printf("1");  
        else  
            printf("0");    
    }    
    puts("");
}    
int main()  
{  
    for(int i=0;i<=31;i++) 
        write(i);
    return 0;  
}  

Problem D: 2n皇后问题

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 12   Solved: 9
[ Submit][ Status][ Web Board]

Description

给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

Input

 输入的第一行为一个整数n,表示棋盘的大小。接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。

Output

 输出一个整数,表示总共有多少种放法。

Sample Input

4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1

Sample Output

20

【分析】

本场比赛最难的题了吧应该算是.....基础dfs...
做两次n皇后问题就可以了,两层dfs,dfs写法很多种,无所谓怎么写,数据n<=8所以直接爆搜不会超时的...
本人比较懒所以这个代码在我心里是属于第二级别的...个人认为最好的代码风格应该是分成两个dfs写
dfs先搜黑皇后摆放,放完之后dfs再搜一次白皇后摆放,因为黑白皇后互相之间没有影响,唯一的影响只有点是否占领,这道题里棋盘中是有位置不能放皇后的,所以需要
//1表示当前位能放皇后
//2表示当前位放白(黑)皇后
//3表示当前位放黑(白)皇后
放置黑白皇后的先后对答案没有影响...
【代码】
#include <stdio.h>
#include <string.h>
int a[20][20];  
int sum;
int n; 
int judge(int i,int j,int k)
{
    for(int r=0;r<n;r++)
        if(a[r][j]==k)    
            return false; 
    for(int c=0;c<n;c++)
        if(a[i][c]==k)    
            return false; 
    for(int r=i-1,c=j-1;r>=0&&c>=0;r--,c--)             
        if(a[r][c]==k)                          
            return false;  
    for(int r=i+1,c=j+1;r<n&&c<n;r++,c++)                
        if(a[r][c]==k)                          
            return false; 
    for(int r=i-1,c=j+1;r>=0&&c<n;r--,c++)     
        if(a[r][c]==k)                          
            return false; 
    for(int r=i+1,c=j-1;r<n&&c>=0;r++,c--)       
        if(a[r][c]==k)                          
            return false; 
    return true;   
}
void find(int i,int flag)    
{
    if(i>=n)
    {
        if(!flag) {sum++;flag=1;return;}
        flag=0;   
        i=0;
    }
    if(flag)     
    {
        for(int j=0;j<n;j++)
            if(judge(i,j,2)&&a[i][j]==1)
            {
                a[i][j]=2; 
                find(i+1,flag);
                a[i][j]=1; 
            }    
    } 
    else
    {
        for(int j=0;j<n;j++)
            if(judge(i,j,3)&&a[i][j]==1)
            {
                a[i][j]=3; 
                find(i+1,flag);
                a[i][j]=1; 
            }
    }
}
int main()
{
    while (~scanf("%d",&n))
    {
        memset(a,0,sizeof(a));
        sum=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&a[i][j]);
        find(0,1);
        printf("%d\n",sum);
    }
    return 0;
 } 

Problem E: 勇者斗恶龙

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 1032   Solved: 394
[ Submit][ Status][ Web Board]

Description

你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头)。村里有m个骑士可以雇佣,一个能力值为x的骑士可以砍掉恶龙一个直径不超过x的头,且需要支付x个金币。如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍掉一个头(且不能被雇佣两次)。

Input

输入包含多组数据。每组数据的第一行为正整数n和m(1<=n,m<=20 000);以下n行每行为一个整数,即恶龙每个头的直径;以下m行每行一个整数,即每个骑士的能力。

输入结束标志为n=m=0。

Output

对于每组数据,输出最少花费。如果无解,输出“Loowater is doomed!”。

Sample Input

2 3
5
4
7
8
4
2 1
5
5
1 0
0 0

Sample Output

11
Loowater is doomed!

【分析】

也算是基础贪心吧,首先对龙和骑士的能力分别进行排序,然后两个指针i表示当前第i个头,指针j表示当前第j个骑士,如果当前骑士可以杀掉当前头,就用当前骑士杀掉这个头,如果不能,则j++找下一个骑士,如果骑士用完了头还没杀完就是Loowater is doomed!
这里因为数据较小,所以我用直接标记记录骑士的能力值的方法,每次判断是否存在能力和第i个头能力相同的骑士,如果没有,则给第i个头的能力值+1,直到找到能杀掉这个头的骑士或者找不到骑士则Loowater
这个方法的速度好像是比排序来的快一点点的...但是对于这种数据这种优化依然没有什么意义....
【代码】
#include <stdio.h>
int n,m;
int a[30000]={0};
int b[30000]={0};
int main()
{
    while (~scanf("%d%d",&n,&m)&&(n||m))
    {
        int i,max=0,sum=0,rider,t=0;
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        for (i=1;i<=m;i++) 
        {
            scanf("%d",&rider);
            b[rider]++;
            if (rider>max) max=rider;
        }
        for (i=1;i<=n;i++)
        { 
            while (b[a[i]]==0 && a[i]<=max) {a[i]++;}
            if (a[i]>max) 
            {
                t=1;
                break;
            }
            b[a[i]]--;
            sum+=a[i];
        }
        if (t==1) 
            printf("Loowater is doomed!\n");
        else
            printf("%d\n",sum);
        for (i=1;i<=max;i++) b[i]=0;
    }
}

Problem F: 工程

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 108   Solved: 70
[ Submit][ Status][ Web Board]

Description

某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。

现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

Input

本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数NM(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

 


 

Output

对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从ST的路线,就输出-1.

Sample Input

3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2

Sample Output

2
-1

【分析】

标准的最短路模板...不过标准的最短路也没有什么模板这种说法...翻模板还不如自己直接敲快的多....
bfs或者弗洛伊德算法都可以反正数据依然很小....
//因为我个人很少用弗洛伊德算法...所以刚好有这个机会稍微练习一下这个算法就用了...
【代码】
#include <stdio.h>
#include <algorithm>
#define inf 0x3f3f3f3f 
int f[250][250];  
int n,m;  
int main()  
{  
    int a,b,x,s,t,ans;  
    while(~scanf("%d %d",&n,&m))  
    {  
        for(int i=0;i<n;i++)  
            for(int j=0;j<n;j++)  
                f[i][j]=(i==j?0:inf);  
        while(m--)  
        {  
            scanf("%d %d %d",&a,&b,&x);  
            if(x<f[a][b])  
                f[a][b]=f[b][a]=x;  
        }  
        scanf("%d%d",&s,&t);  
        for(int t = 0;t < n;t++)  
            for(int i = 0;i < n;i++)  
                for(int j = 0;j < n;j++)  
                    if(f[i][j] > f[i][t] + f[t][j])  
                        f[i][j] = f[i][t] + f[t][j];  
        printf("%d\n",f[s][t]==inf?-1:f[s][t]);
    }  
    return 0;  
}  


Problem G: 矩形A + B

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 196   Solved: 163
[ Submit][ Status][ Web Board]

Description

给你一个高为n ,宽为m列的网格,计算出这个网格中有多少个矩形,下图为高为2,宽为4的网格.

Input

第一行输入一个t, 表示有t组数据,然后每行输入n,m,分别表示网格的高和宽 ( n < 100 , m < 100).

Output

每行输出网格中有多少个矩形.

Sample Input

2
1 2
2 4

Sample Output

3
30

【分析】

数据依然很小....找找规律就好了...当然如果真的...找不到规律...实在不行就打表吧.....反正数据也小...但是还是那句话,不存在超时的情况,打表就没有意义...
所以不如算一算啊,数一数啊,找找规律啊~什么的最有爱了
如果只看一行的话,长度为1的有m个,长度为2的有m-1个……,长度为m的有1个。
那么每一行就有:1+2+3+……+m个=m * (m + 1) / 2。
然后再竖过来看每一列也是一样的:1+2+3+……+n个=n * (n + 1) / 2。
所以横竖两种可能乘一下就好了...答案就是(1+m)*m/2*(1+n)*n/2
//这件事告诉我们小学奥数学的好是多么的重要....幸好之前之江学院的比赛复习了一大波小学奥数题....
【代码】
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int main()
{
    int t;scanf("%d",&t);
    for (int p=0;p<t;p++)
    {
        int n,m,sum1,sum2;
        scanf("%d %d",&n,&m);
        sum1=(1+n)*n/2;
        sum2=(1+m)*m/2;
        printf("%d\n",sum1*sum2);
    }
    return 0;
}

Problem H: 字母图形

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 81   Solved: 41
[ Submit][ Status][ Web Board]

Description

问题描述 利用字母可以组成一些美丽的图形,

下面给出了一个例子:

ABCDEFG

BABCDEF

CBABCDE

DCBABCD

EDCBABC

这是一个5行7列的图形,请找出这个图形的规律,并输出一个n行m列的图形。

Input

  输入一行,包含两个整数n和m,分别表示你要输出的图形的行数的列数。 数据规模与约定 1 < = n, m < = 26。

Output

 输出n行,每个m个字符,为你的图形。

Sample Input

5 7

Sample Output

ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC

【分析】

找规律输出的一道题...没什么好说的
【代码】
#include <stdio.h>
int main()
{
    int n,m;
    while (~scanf("%d%d",&n,&m))
    {
        for (int i=0;i<n;i++)
        {
            int j=0;
            for (char a='A'+i;a>'A'&&j<m;a--)
            {
                printf("%c",a);
                j++;
            }
            for (char a='A';a<='Z'&&j<m;a++)
            {
                printf("%c",a);
                j++;
            }
            puts(""); 
        }
    }
    return 0;
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值