天梯赛选拔赛(一)题解

最后一位

时间限制: 1 Sec  内存限制: 128 MB
提交: 226  解决: 30
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

2018年内蒙古自治区大学生程序设计竞赛的冠军选手——李彪,遇到了一个困难的编程问题。他现在手里有N个正整数,他以N作为基数,然后依次对手里的N个数进行如下操作:如果当前遇见的数是偶数就用之前的基数乘以它,如果当前遇见的数是奇数就用之前的基数加上它,运算完成后的结果重新再作为基数,然后重复上述步骤,直到所有N个数都运算完成。李彪想知道当运算完成后,最终得数的最后一位数是多少? 

输入

先输入一个正整数N ( 1<= N <= 1000 ) 
接下来输入 N 个正整数,数值均不超过 2147483647,以空格分隔。 

输出

输出最终的得数的最后一位数,输出数据后需要输出回车换行。 

样例输入

5

2 3 4 5 6

样例输出

2

因为只算最后一位所以对最后一位操作就可以,因为加和乘都是可以在最后一位清算的。

#include <iostream>

 

using namespace std;

 

int main()

{

    int n;

    while(cin >> n)

    {

        int x = n;

        for(int i = 0; i < x; i++)

        {

            int t ;

             cin >> t;

             if(t & 1)

             {

                n = (n + t % 10) % 10;

             }

             else

             {

                n = (n * (t % 10)) % 10;

             }

        }

        cout << n << endl;

    }

    return 0;

}

 

哈夫曼树的根值

时间限制: 1 Sec  内存限制: 128 MB
提交: 34  解决: 5
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为: 

(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点); 

(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和; 

(3)从森林中删除选取的两棵树,并将新树加入森林; 

(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。 
如:对 下图中的六个带权叶子结点来构造一棵哈夫曼树,步骤如下: 


现在给定构造哈夫曼树的N(2<=N<=100000)个权值,请问当哈夫曼树构造完成后,根节点及根节点的较大子节点的权值是多少?

输入

首先输入开始的权值个数N,接下来输入N个正整数,范围均在1~100,以空格分隔。 

输出

输出哈夫曼树根节点及根节点的较大子节点的权值,以空格分隔,输出完成后需要输出回车换行。 

样例输入

6

9 12 6 3 5 15

样例输出

50 29

提示

本例中生成的哈夫曼树中每个结点的左子树根结点的权小于等于右子树根结点的权。虽然哈夫曼树形状可能不同,单数根节点权值是唯一的。 

看似让你构造曼哈顿树,实则是对一个队列进行离线排序取出最小的前俩项在合并放进队列里,可以手写一个优先队列,或者直接套C++STL容器priority_queue,注意要将优先级改成最大值优先,这样就会将最小值排在前面。

 

 

#include <iostream>

# include <string>

# include <queue>

# include <functional>

 

using namespace std;

 

const int maxn = 10005;

 

 

 

int main()

{

    int n;

    while(cin >> n)

    {

        priority_queue<int, vector<int>, greater<int> > q;

 

        for(int i = 0; i < n; i++)

        {

            int x;

            cin >> x;

            q.push(x);

        }

        while(q.size() > 2)

        {

            int s1 = q.top();

            q.pop();

            int s2 = q.top();

            q.pop();

            q.push(s1 + s2);

        }

        int s1 = q.top();

        q.pop();

        int s2 = q.top();

        q.pop();

        cout << s1 + s2 << " " << max(s1 , s2) << endl;

    }

    return 0;

}

求解GCD

时间限制: 1 Sec  内存限制: 128 MB
提交: 203  解决: 38
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

ACMer知道GCD方法是用于计算两个数的最大公约数的,现在ACMer遇到的问题依然很简单,就是计算两个数的最大公约数,而此时,这两个是不再是简单的a和b两个数,而是给定两个数a和b,需要计算的是 a! 和 b! 的最大公约数,即GCD( a! , b ! ) 

输入

输入两个正整数,a和b,空格分隔。(1<=a,b<=20) 

输出

输出a!和b!的最大公约数,输出数据后需要输出回车换行。 

样例输入

4 2

样例输出

2

提示

4!==24 ; 2!==2 ; gcd( 24,2 ) == 2; 

 

 

看似俩个阶乘求最大公共因子特别麻烦,实则是一道水题, 如3!和5!铁定是小的是最大公约数。

 

#include <iostream>

 

using namespace std;

 

int main()

{

    int a, b;

    while(cin >> a >> b)

    {

        long long int x = 1;

        if(a < b)

        {

            for(int i = 1; i <= a; i++)

            {

                x *= i;

            }

        }

        else

        {

            for(int i = 1; i <= b; i++)

            {

                x *= i;

            }

        }

        cout <<x<< endl;

    }

    return 0;

}

 

调酒师

时间限制: 1 Sec  内存限制: 128 MB
提交: 87  解决: 14
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

WAer是ACM国际大酒店的一名调酒师,他现在有10种不同的原料酒。光临ACM大酒店的顾客们喜欢各种各样的酒,WAer的工作就是为他们调酒,WAer调酒的时候,每种原料酒至少会放1克,最多放会5克 ,不同原料放入顺序不影响最终结果,调完之后酒的价值就是其使用的原料酒的质量之和。现在来了一位顾客,他想要让WAer给他调质量为n的酒,那么有多少种不同的方案呢? 

输入

输入一个正整数n (0<=n<=1000000) 

输出

首先一行输出可以调酒的方案数。 

然后再按照字典序排列输出每种原料酒的质量,各原料质量之间以空格分隔,每行一种方案。 
如果没有符合要求的方法,就只要输出0并回车换行。具体参见样例。 

样例输入

11

样例输出

10

1 1 1 1 1 1 1 1 1 2

1 1 1 1 1 1 1 1 2 1

1 1 1 1 1 1 1 2 1 1

1 1 1 1 1 1 2 1 1 1

1 1 1 1 1 2 1 1 1 1

1 1 1 1 2 1 1 1 1 1

1 1 1 2 1 1 1 1 1 1

1 1 2 1 1 1 1 1 1 1

1 2 1 1 1 1 1 1 1 1

2 1 1 1 1 1 1 1 1 1

提示

注意每行数据之间有空格,最后一个数后面不是空格,而是直接回车换行。 
字典序是指优先输出前面的原料且优先按照从小到大排列。 

暴力出奇迹,算一下5^10是不到1千万,可以直接暴力,注意要用c的输入输出,c++的会超时

 

 

#include <iostream>

# include <string>

# include <queue>

# include <functional>

# include <cstdio>

 

using namespace std;

 

const int maxn = 500005;

//48828125

 

int arr[maxn][11];

 

int main()

{

 

 

    int n;

    while(scanf("%d",&n) !=EOF)

    {

        if(n < 10 || n > 50)

        {

            printf("0\n");

        }

        else

        {

            int m= 0;

            for(int a = 1; a <= 5; a++)

                for(int b = 1; b <= 5; b++)

                    for(int c = 1; c <= 5; c++)

                        for(int d = 1; d <= 5; d++)

                            for(int e = 1; e <= 5; e++)

                                for(int f = 1; f <= 5; f++)

                                    for(int g = 1; g <= 5; g++)

                                        for(int h = 1; h <= 5; h++)

                                            for(int i = 1; i <= 5; i++)

                                                for(int j = 1; j <= 5; j++)

                                                {

                                                    if(a + b +c + d + e + f+ g + h + i + j == n)

                                                    {

                                                        arr[m][0] = a;

                                                        arr[m][1] = b;

                                                        arr[m][2] = c;

                                                        arr[m][3] = d;

                                                        arr[m][4] = e;

                                                        arr[m][5] = f;

                                                        arr[m][6] = g;

                                                        arr[m][7] = h;

                                                        arr[m][8] = i;

                                                        arr[m][9] = j;

                                                        m++;

                                                    }

                                            }

printf("%d\n", m);

                for(int i = 0; i < m; i++)

                {

                    int p = 0;

                    for(int j = 0; j < 10; j++)

                    {

                        if(p++)

                        {

                            printf(" ");

                        }

                        printf("%d",arr[i][j]);

                    }

                    printf("\n");

                }

        }

    }

    return 0;

}

 

 

蚂蚁森林畅玩版

时间限制: 1 Sec  内存限制: 128 MB
提交: 36  解决: 8
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

Accepted正在玩蚂蚁森林,他想要收集一些能量球种树,树的价值就是在种这棵之前收集的能量球的能量之和。Accepted拥有的能量球种类有无限种,按照价值从小到大来分类,他的能量球可以这样分:2、3、5、7、11、13….是的,你猜对了,他的每一种能量球的能量就是一个素数! 

在Accepted的蚂蚁森林里面,收集一个能量球的能量之后,这个能量球会消失,但神奇的是,系统会立刻再重新生成一个一模一样的能量球。 
Accepted的蚂蚁森林真是太好玩了,现在他想要种一棵能量值为N的树,他可以有多少种不同的收集能量球的方法呢?不同的方法是指收集能量球的不同组合方案数、与收集顺序无关。 

输入

输入一个正整数N(1<=N<=1000),代表要种的树需要的能量总价值。 

输出

输出不同的能量球组合方案,每组输出占一行。 

样例输入

7

样例输出

3

提示

第一种:收集1个价值为7的能量球(7=7) 

第二种:收集1个价值为2的和1个价值为5的(7=2+5)。(但这与1个价值为5的和1个价值为2的方案相同) 
第三种:收集1个价值为3的和2个价值为2的。(7=2+2+3)与(7=2+3+2、7=3+2+2)算为一种。 

递推题,找规律。

#include <iostream>

# include <string>

 

using namespace std;

 

const int maxn = 10005;

 

int arr[maxn], prime[maxn];

 

void fun()

{

    int s = 1;

    arr[0] = arr[1] = 1;

    for(int i = 2; i < maxn; i++)

    {

        if(!arr[i])

        {

            prime[s++] = i;

        }

        for(int j = 1; j < s && i * prime[j] < maxn; j++)

        {

            arr[i * prime[j]] = true;

            if(i % prime[j] == 0)

            {

                break;

            }

        }

    }

 

}

 

int main()

{

    fun();

    int n;

    while(cin >> n)

    {

        long long int dp[maxn] = {0};

        dp[0] = 1;

        for(int i = 1; prime[i] <= n; i++)

        {

            for(int j = prime[i]; j<= n; j++)

            {

                dp[j] += dp[j - prime[i]];

            }

        }

        cout << dp[n] << endl;

    }

    return 0;

}

 

 

构建题目集

时间限制: 1 Sec  内存限制: 128 MB
提交: 6  解决: 3
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

C语言老师在要在PTA平台上面编辑一套期末考试题目,以检验大家的学习效果。现在老师手里已经有N个题目可供选择,题目编号1, 2 … N。每个题目对应的分数依次为S1, S2 … SN。老师构建题目集的规则如下: 

1.       至少从N个题目里面选取2个题目才能构建一个题目集 

2.       在构建的题目集中所有题目的分数之和必须大于等于L并且小于等于R 

3.       同一题目集中分数最大的题目和分数最小的题目的分数之差必须大于等于X 
老师现在只关心题目的选取问题,题目次序不考虑,请问老师构建题目集共有多少种满足条件的方案? 

输入

首先输入N(1<=N<=15)、L、R(1<=L<=R<=109)、X(1<=X<=106),以空格分隔。接下来输入N个候选题目的分数S1, S2 … SN(1<=Si<=106),以空格分隔。输入详见样例。 

输出

构建题目集共有多少种满足条件的方案,输出后还需要输出回车换行。 

样例输入

3 5 6 1

1 2 3

 

4 40 50 10

10 20 30 25

 

5 25 35 10

10 10 20 10 20

样例输出

2

2

6

提示

样例1:(选第2、3题);(选第1、2、3题) 共两种方案。 

样例2:(选第1、2题) ;(选第2、3题) 共两种方案。 
样例3:选一个10分和一个20分的题目即可,而且只能这样,共六种方案。

搜索题,搜就可以了

 

# include <iostream>

# include <cstring>

# include <string>

# include <cstdio>

# include <functional>

# include <queue>

# include <cmath>

# include <vector>

# include <set>

# include <algorithm>

 

using namespace std;

const int maxn = 20;

 

int n, l,r, x;

int c;

int arr[maxn];

int book[maxn];

 

void dfs(int flag, int sum, int maxx, int minn, int z)

{

 

    if(maxx - minn >= x && sum >= l  && sum <= r &&z >= 2)

    {

        c++;

    }

    if(flag >= n)

    {

        return ;

    }

 

    for(int i = flag; i < n; i++)

    {

        dfs(i+ 1, sum + arr[i], max(maxx, arr[i]), min(minn, arr[i]), z + 1);

    }

    return ;

}

 

 

int main(int argc, char *argv[])

{

    while(cin >> n >> l >> r >> x)

    {

        c = 0;

        for(int i = 0; i < n; i++)

        {

            cin >> arr[i];

        }

        sort(arr, arr + n);

        dfs(0, 0, 0, 0x3f3f3f3f, 0);

        cout <<c <<endl;

    }

    return 0;

}

 

 

 

 

盗墓笔记之沙帮王国

时间限制: 1 Sec  内存限制: 128 MB
提交: 27  解决: 10
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

王胖子已经在深山老林里面转了好久,他终于找到了传说中沙帮王国的王室墓葬的入口…… 

可是让他郁闷的是,进入这个入口需要输入密码,王胖子气得要死,先坐下来抽根烟儿压压惊…… 

王胖子很聪明,他突然回忆起来。早些年三叔给过他一张关于沙帮王国的秘密图纸…… 

王胖子在自己的装备里面找了半天,终于找到了这张图,他仰天大笑,终于可以得到宝贝了…… 

他再一看图,又仰天大哭,三叔给他的是一张写满了O和X的破纸,而且还假装很工整…… 

王胖子又躺下来抽根烟儿,心想这,这三叔就是个坑货,什么破图纸,怎么可能进入墓葬…… 

他气得睡着了,梦里梦见了他的多年老友大金牙,梦里大金牙对他说了一句话,“最大,十字哦!” 

王胖子秒醒,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈,我知道密码是啥了,他又仰天大笑…… 

他明白了,原来就是要在这图纸上,找出一个最大的十字! 

可是图上有两种符号,到底以哪个为准呢?王胖子很聪明,他把大金牙的话念了100遍,胸有成竹的说:密码就是:在这图纸上找出O符号构成的连续的最大的中心对称的十字,密码就是这个十字的臂长!!!,哈哈哈哈哈哈哈哈哈哈……王胖子笑得都抽筋了…… 

他冷静下来,看了看图纸,顿时懵*,这么密密麻麻的字,这得找到哪辈子才能找到最大的啊,而且看一会眼睛就花了……呜呜呜呜呜呜呜呜呜,他又哭起来…… 

哈哈哈哈哈哈哈哈哈,我有办法了,王胖子大叫,我把这破图拍照,发给吴邪,那小子肯定有办法秒解答案啊,哈哈哈哈哈哈哈…….. 

不一会,他收到了吴邪传给他的答案,他进入古墓,得到了心仪已久的沙帮王国的木乃伊公主…… 

可是他万万不知道,吴邪并没有他想的那么神,无邪只是把这张图看成是一个二维的字符矩阵,然后自己做了一些扫描和文字识别之类的处理,最后又写了一段很牛的程序,就把答案就分析出来了。 
现在,你需要写出这样一个程序,帮助王胖子破解密码。 

输入

首先输入一个正整数N,代表字符矩阵的大小为N行N列。( 1<= N<= 1000 ) 
然后输入N行N列的字符矩阵,每个字符只会是O或X。 

输出

输出由O构成的最大的中心对称的十字的臂长,如果找不到十字,则输出0。然后输出回车换行。(提示:十字的臂长是指,从十字的中心到十字的四个臂一端的长度,这里考虑中心对称十字,所以四个臂长肯定是一样的。一个O认为是臂长为1的十字)。详见样例。 

样例输入

5

XXOXX

XXOOX

OOOOO

XXOOO

XXOXX

样例输出

3

提示

以第三行第三列为中心的中心对称十字的臂长最大,臂长为3。 

跟oj上的mh370很像,一圈一圈找就行了。

 

#include <iostream>

# include <string>

# include <queue>

# include <functional>

# include <cstdio>

# include <cstring>

 

using namespace std;

 

const int maxn = 1005;

  char ch[maxn][maxn];

int main()

{

 

 

    int n;

    while(scanf("%d",&n) !=EOF)

    {

       memset(ch, false, sizeof(ch));

        for(int i = 0; i < n; i++)

        {

            cin >> ch[i];

        }

        int s = 0;

        for(int i = 1; i < n; i++)

        {

            for(int j = 1; j < n; j++)

            {

                if(ch[i][j] == 'O' && ch[i - 1][j] == 'O' && ch[i + 1][j] == 'O' && ch[i][j - 1] == 'O' && ch[i][j + 1] == 'O')

                {

                    int c= 2;

                    for(int k = 2; k < n; k++)

                    {

                        if(ch[i ][j] == 'O' && ch[i - k][j] == 'O' && ch[i + k][j] == 'O' && ch[i][j - k] == 'O' && ch[i][j + k] == 'O')

                        {

                            c++;

                        }

                        else

                        {

                            break;

                        }

                    }

 

                    s = max(s, c);

                }

            }

        }

        cout << s << endl;

    }

    return 0;

}

OnlineJudge

时间限制: 1 Sec  内存限制: 128 MB
提交: 80  解决: 29
[提交] [状态] [讨论版] [命题人:*Administrator]

题目描述

OnlineJudge系统可以支持多种编程语言,目前我们的系统可以扩展支持如下:
GO, JavaScript, Lua, Clang++, Clang, Schema, FreeBasic, Obj-C, C#, Perl, PHP, Python, Bash, Ruby, Java, Pascal, C++, C
总共18项语言支持。系统管理员在管理语言支持的时候不会单独操作某一种语言,而是通过给出一个十进制整数就可以修改所有的语言支持。原理是这样的,管理员把所有的语言看成是二进制的位,如果系统支持这个语言,那么就把对应位置的二进制位置为1,如果不支持这个语言,就把对应位置的二进制位置为0,GO语言代表最高位,C语言代表最低位。例如,系统如果只支持C语言的话,只有最低位是1,其余位全部为零,则所有语言对应的二进制位构成的十进制整数为1;如果系统支持C和C++,则所有语言对应的二进制位构成的十进制整数为2;现在你想知道系统都支持什么语言,而当你询问管理员的时候,管理员给你的回答不是到底支持什么语言,而是给你一个表示所有语言支持的整数,那么你能否通过这个整数分析出来系统到底支持那些语言呢?

输入

输入一个正整数(数据保证对应上面所有语言并在正确的范围内) 

输出

按照从前到后的顺序输出输出给定整数所支持的所有语言,每行一个。 

样例输入

3

75

样例输出

C++

C

 

Python

Java

C++

C

提示

就是求二进制,只不过语言表是反的,倒转一下就可以。

 

#include <iostream>

# include <string>

 

using namespace std;

 

string str[19] = {"GO", "JavaScript", "Lua", "Clang++", "Clang", "Schema", "FreeBasic", "Obj-C", "C#", "Perl", "PHP", "Python", "Bash", "Ruby", "Java", "Pascal", "C++", "C"};

const int maxn = 19;

 

int main()

{

    int n;

    while(cin >> n)

    {

        bool flag[maxn] = {0};

        string s[maxn];

        for(int i = 17,k = 0; i >= 0; i--)

        {

            s[k++] = str[i];

        }

        int c = 0;

        while(n)

        {

            if(n % 2)

            {

                flag[c] = true;

            }

            n /= 2;

            c++;

        }

        for(int i = c - 1; i >=0 ; i--)

        {

            if(flag[i])

            {

                cout << s[i] << endl;

            }

        }

    }

    return 0;

}

 

猜你喜欢

转载自blog.csdn.net/I_O_fly/article/details/88380132