2020-11-29 题目练习总结

直达我的博客主页(gitee版)

2020-11-29 题目练习总结(完善中)1

第一题

Sky数 2

题目
熊熊学长从小喜欢奇特的东西,而且天生对数字特别敏感,一次偶然的机会,他发现了一个有趣的四位数2992,这个数,它的十进制数表示,其四位数字之和为2+9+9+2=22,它的十六进制数BB0,其四位数字之和也为22,同时它的十二进制数表示1894,其四位数字之和也为22,啊哈,真是巧啊。熊熊学长非常喜欢这种四位数,由于他的发现,所以这里我们命名其为Sky数。但是要判断这样的数还是有点麻烦啊,那么现在请你帮忙来判断任何一个十进制的四位数,是不是Sky数吧。

Input
输入含有一些四位正整数,如果为0,则输入结束。

Output
若n为Sky数,则输出“#n is a Sky Number.”,否则输出“#n is not a Sky Number.”。每个结果占一行。注意:#n表示所读入的n值。

Sample Input
2992
1234
0

Sample Output
2992 is a Sky Number.
1234 is not a Sky Number.

分析

将该数字利用 scanf 接收,并将其分别转化为十二、十六进制(可以利用函数),并比较该数在不同进制下各位之和(注意比较时的逻辑问题),相同输出 #n is a Sky Number. ,反之输出 #n is not a Sky Number.

解答
#include <stdio.h>
int main(void)
{
    int a[10000];
    int count = 0, val1, val2, val3;
    int num1, num2, num3;
    for (int i = 0; 1; i++)
    {
        scanf("%d", &a[i]);
        if (a[i] == 0)
        {
            break;
        }
        count++;
    }
    /* 以上是定义及输入部分 */
    for (int i = 0; i < count; i++)
    {
        val1 = val2 = val3 = 0;
        num1 = num2 = num3 = 1; 
        for (int j = 0; 1; j++)
        {
            val1 += a[i] / num1 % 10;
            val2 += a[i] / num2 % 12;
            val3 += a[i] / num3 % 16;
            num1 *= 10;
            num2 *= 12;
            num3 *= 16;
            if (a[i] / num1 == 0 && a[i] / num2 == 0)
            {
                break;
            }
        }
        /* 进制转换 */
        if (val1 == val2 && val2 == val3)
        {
            printf("%d is a Sky Number.\n", a[i]);
        }
        else
        {
            printf("%d is not a Sky Number.\n", a[i]);
        }
        /* 比较并输出 */
    }
    return 0;
}

第二题

哥德巴赫来了可能有用吧3

题目
倩倩学姐想把一个偶数拆成两个不同素数的和,你有有几种拆法呢?

Input
输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束。

Output
对应每个偶数,输出其拆成不同素数的个数,每个结果占一行。

Sample Input
30
26
0

Sample Output
3
2

分析

方法一:暴力枚举法(易TLE
  先将该组偶数接收(接受结果为0时利用 break; 跳出),并逐一暴力尝试(注意简化判断素数时的方法,判素数时可以使 i <= sqrt{max}),并批量输出该组数(注意格式)。

方法二:打表
  将范围内的所有素数判断出来(同样记得简化),接收该组数并判断拆法,输出答案。

解答
#include <stdio.h>
int pend(int a)
{
    for (int i = 2; i * i <= a; i++)
    {
        if (!(a % i))
        {
            if (i != a)
            {
                return 0;
            }
        }
    }
    return 1;
    /* 利用函数判断a是不是素数 */
}
int main(void)
{
    int a[501];
    int count = 0, b, c, ans;
    for (int i = 0; 1; i++)
    {
        scanf("%d", &a[i]);
        if (a[i] == 0)
        {
            break;
        }
        count++;
    }
    /* 定义及输入部分 */
    for (int i = 0; i < count; i++)
    {
        b = 3, ans = 0;
        for (int j = 3; j < a[i] / 2; j++)
        {
            if (pend(j) && pend(a[i] - j) && b != c)
            {
                ans++;
            }
        }
        printf("%d\n", ans);
    }
    /* 判断及输出部分 */
    return 0;
}

第三题

咦!这是嘛呀!4

题目
现在我们有两个正整数A和B,请找出一个正整数C,使得式子((A xor C) & (B xor C))最小(xor是异或运算)。
当然,如果使得式子最小的C为0时,请你输出1。

Input
第一行输入T,代表有T组数据。
接下来每一行输入两个数A,B(A,B<=2^32)

Output
对于每一组数据输出一个正整数C

Sample Input
1
3 5

Sample Output
1

分析

本题需了解位运算相关知识
&:按位相与
xor(^):按位异或
真值表

abba&ba^b
111100
100/1010
010/1010
001000

之后开始分析本题
  由上表知,若要使((A ^ C) & (B ^ C))最小,则只需 C = A & B
  若C = 0,则输出1,反之输出C。

解答
#include <stdio.h>
int main(void)
{
    int n;
    scanf("%d", &n);
    long long a[1000][2];
    for (int i = 0; i < n; i++)
    {
        scanf("%lld%lld", &a[i][0], &a[i][1]);
    }
    /* 定义及输入部分 */
    for (int i = 0; i < n; i++)
    {
        long long int c = a[i][0] & a[i][1];
        if (!c)
            printf("1\n");
        else
            printf("%lld\n", c);
    }
    /* 计算及输出部分 */
    return 0;
}

第四题

倩姐的自我突破5

问题
倩倩学姐,一个大三的老阿姨呢,但是呢她还有一颗坚持竞赛的心。所以他碰到一个奥林匹克竞赛的数学问题,她搞不定很难受,决定暴饮暴食。聪明而优秀的学霸熊熊学长看到这一幕决定帮他解决这个问题。这个问题是:
我们描述 K:
k! = 1 * 2 * …* (k - 1) *k
我们表示 S:
S = 1 * 1! + 2 * 2! + … +
(n - 1) * (n-1)!
然后 S 对 n 去模是 ___________
你将得到一个整数n.
你需要计算 S 对 n 取模的值

输入
第一行输入一个整数 T(T < 1000), 表示测试用例的行数.
对于每个测试用例,都有一行包含一个整数 n.
保证 2 <= n <= 10^18

输出
对于每个测试用例,打印一个整数 S 对 n 取模后的值.

提示
第一个测试用例 S = 1* 1!= 1, 并且 1 的模 2 运算 1.
第二个测试用例 S = 11!+2 2!= 5 , 并且 5 对 3 取模是 2.

Sample Input
2
2
3

Sample Output
1
2

分析

1 + S(n)
= 1 + 1 × 1! + 2 × 2! + ⋯ + (n − 1) × (n − 1)!
= 2 × 1! + 2 × 2! + ⋯ + (n − 1) × (n − 1)!
= 2! + 2 × 2! + ⋯ + (n − 1) × (n − 1)!
= 3 × 2! + ⋯ + (n − 1) × (n − 1)!
= 3! + 3 × 3! + ⋯ + (n − 1) × (n − 1)! = 4 × 3! + ⋯ + (n − 1) × (n − 1)!
= ⋯ = (n − 1)! + (n − 1) × (n − 1)! = n × (n − 1)!
= n!

S(n) mod n
= (n! − 1) mod n
= (n! + n − 1) mod n
=n! mod n + (n − 1) mod n
= n − 1

利用数学知,我们只需接收n,并输出n - 1。

解答
#include <stdio.h>
int main(void)
{
    long long n, ans;
    scanf("%lld", &n);
    while (n--)
    {
        scanf("%lld", &ans);
        printf("%lld\n", ans - 1);
    }
    return 0;
}

第五题

看看就好,劝一下自己6

问题
古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为:
1+2+4+5+10+11+20+22+44+55+110=284。
而284的所有真约数为1、2、4、71、 142,加起来恰好为220。人们对这样的数感到很惊奇,并称之为亲和数。一般地讲,如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。
你的任务就编写一个程序,判断给定的两个数是否是亲和数

Input
输入数据第一行包含一个数M,接下有M行,每行一个实例,包含两个整数A,B; 其中 0 <= A,B <= 600000 ;

Output
对于每个测试实例,如果A和B是亲和数的话输出YES,否则输出NO。

Sample Input
2
220 284
100 200

Sample Output
YES
NO

分析

方法一:(易TLE
  输入、分别计算两数的真约数之和并比较、输出。

方法二:
  将范围内的数的真约数和打表,输入、比较、输出。

解答
#include <stdio.h>
int main(void)
{
    int n;
    scanf("%d", &n);
    int a[1000][2];
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d", &a[i][0], &a[i][1]);
    }
    /* 定义及输入部分 */
    int b1, b2;
    for (int i = 0; i < n; i++)
    {
        b1 = b2 = 0;
        for (int j = 1; j < a[i][0]; j++)
        {
            if (!(a[i][0] % j))
                b1 += j;
        }
        for (int j = 1; j < a[i][1]; j++)
        {
            if (!(a[i][1] % j))
                b2 += j;
        }
        /* 比较部分 */
        if (b1 == a[i][1] && b2 == a[i][0])
            printf("YES\n");
        else
            printf("NO\n");
        /* 输出部分 */
    }
    return 0;
}

第六题

熊熊的尝试7

问题
熊熊学长一天在实验室里闲的没事。他想做点游戏打发一下时间。他就拉上了和他同样无聊的柴柴学长。
两位学长要玩的游戏是什么呢?很简单,它是这样定义的:
1、 本游戏是一个二人游戏;
2、 有一堆石子一共有n个;
3、 两人轮流进行;
4、 每走一步可以取走1…m个石子;
5、 最先取光石子的一方为胜;
如果游戏的双方使用的都是最优策略,请输出哪个人能赢。

Input
输入数据首先包含一个正整数C(C<=100),表示有C组测试数据。
每组测试数据占一行,包含两个整数n和m(1<=n,m<=1000),n和m的含义见题目描述。

Output
如果先走的人能赢,请输出“first”,否则请输出“second”,每个实例的输出占一行。

Sample Input
2
23 2
4 3

Sample Output
first
second

分析

该题为巴什博弈(详见链接
  若n能被m + 1整除,此时后手有必胜策略,若n不能被m + 1整除,此时新手有必胜策略。

解答
#include <stdio.h>
int n, b;
int main(void)
{
    scanf("%d", &n);
    int a[1000][2];
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d", &a[i][0], &a[i][1]);
    }
    /* 定义及输入部分 */
    for (int i = 0; i < n; i++)
    {
        if (a[i][0] % (a[i][1] + 1) == 0)
        {
            printf("second\n");
        }
        else
        {
            printf("first\n");
        }
        /* 计算及输出部分 */
    }
    return 0;
}

第七题

该烂怂塔,有啥看的8

问题
熊熊学长是个正儿八经的陕西西安人,那烂怂大雁塔看都不想看,但是他突然发现了这道题,就更不想看那烂怂大雁塔。请你写个程序帮他解决一下问题。
有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。

Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。

Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

Sample Output
30

分析

该题可以利用dp思想(比较麻烦),同时可以利用由下到上的思想来实现最优策略。及由下到上取最大值(贪心)。

解答
#include <stdio.h>
#include <algorithm>
int a[1000][1000];
int b[1000];
int sum;
int main(void)
{
    int n, m, t, o, temp;
    scanf("%d", &n);
    for (int k = 0; k < n; k++)
    {
        scanf("%d", &m);
        o = 1;
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < o; j++)
            {
                scanf("%d", &a[i][j]);
            }
            o++;
        }
        /* 定义及输入部分 */
        t = m;
        for (int j = 0; j < m; j++)
        {
            for (int i = 0; i < t; i++)
            {
                temp = std::max(a[m - j][i], a[m - j][i + 1]);
                a[m - j - 1][i] += temp;
            }
            t--;
        }
        b[k] = a[0][0];
        /* 计算及储存部分 */
    }
    for (int i = 0; i < n; i++)
    {
        printf("%d\n", b[i]);
    }
    /* 输出部分 */
    return 0;
}

第八题

Tyloo的S1mple本人9

题目
熊熊是一名csgo玩家,在沙二驰骋多年的他,显然已经对这个地方了如指掌。他恐怖的定位和风骚的身法以及高超的战术让他的队友后悔来到这个地方。尤其是他的大狙,当他扛着笨重的awp走到中门时,每一声枪响都会有人应声倒地。但是熊熊有个奇怪的癖好,他每一次只杀奇数个数的人,一杀他嫌太少,九杀又太多,所以他每一局他只会打出三杀,五杀或七杀。现在你在他旁边看他打游戏,你看到他杀了n个人,你现在想知道他分别打出了多少个三杀,五杀或七杀。

Input
第一行的整数 t(1<=t<=1000)— 测试用例的个数.
每个测试用例只有一个输入数据 — lrh杀人的总数 n(1<=n<=1000)

Output
如果对于某个测试样例,没有正确的答案,则输出 -1.
否则,输出3个正整数-三杀的个数,五杀的个数,七杀的个数 — 如果存在多个情况,输出任意一种即可

Sample Input
4
30
67
4
14

Sample Output
2 2 2
7 5 3
-1
0 0 2

分析

该题利用由大到小的思想进行解题,具体解释详见代码注释。

解答
#include <stdio.h>
int main(void)
{
    int n;
    scanf("%d", &n);
    int a[1001];
    int b, c, d;
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    /* 定义及输入部分 */
    for (int i = 0; i < n; i++)
    {
        d = 0;
        for (int j = 0; j <= a[i] / 7; j++)
        {
            b = a[i] - j * 7;
            for (int k = 0; k <= b / 5; k++)
            {
                c = b - k * 5;
                if (!(c % 3))
                {
                    printf("%d %d %d\n", c / 3, k, j);
                    d = 1;
                    break;
                }
            }
            if (d)
            {
                break;
            }
        }
        /* 分别判断7,5,3杀的数量,并尽量使3杀最多,以简化运算 */
        if (d == 0)
        {
            printf("-1\n");
        }
    }
    return 0;
}

第九题

可鞥吧10

题目
你有 n个 桶放在一排 , 从左到右开始编号分别为1~n. 最初, 第 i 桶装的水是 ai 升.
你可以把水从一个桶倒到另一个桶。 在这个过程中, 你可以两个选择两个桶 x 和y (第 x个桶不应该为空) 然后从桶x 向桶 y 倒水(可能是所有的水).你可以假设桶的容量是无限的,所以你可以在每个桶里倒入任何数量的水。
如果最多可以倒水 k 次.计算桶中最大和最小水量之间的最大可能差。
举例
如果你有四个桶,每个桶里装5升水,k=1,你可以从第二个桶里倒5升水到第四个桶里,所以桶里的水量是[5,0,5,10],最大和最小的差值是10;
如果所有的桶都是空的,你就不能做任何操作,所以最大和最小的量之差仍然是0。

Input
第一行包含一个整数 t (1 < t < 1000) — 测试用例的数量
每个测试用例的第一行包含两个整数 n 和 k(1 <= k < n < 2<= 10^5) — 桶数和可以浇注的数量。
第二行包含 n 整数 a1, a2, … an (0 <=ai <=10^9), 其中ai 是第 i 个桶的初始水量。
保证 n 个以上测试用例的总和不超过 2 * 10^5.

Output
F对于每个测试用例,如果最多可以倒水k 次,请打印桶中最大和最小水量之间的最大可能差值。

Sample Input
2
4 1
5 5 5 5
3 2
0 0 0

Sample Output
10
0

分析

先进行排序,若k不等于0,则后k个元素加起来便是最大可能差值,若等于0,则最后整数中最大数和最小数的差便是最大可能差值。

解答
#include <stdio.h>
#include <algorithm>
int main(void)
{
    long long t, n, k, sum;
    scanf("%lld", &t);
    long long a[200000];
    long long b[1000];
    for (int i = 0; i < t; i++)
    {
        sum = 0;
        scanf("%lld%lld", &n, &k);
        for (int j = 0; j < n; j++)
        {
            scanf("%lld", &a[j]);
        }
        /* 定义及输入部分 */
        std::sort(a, a + n);
        sum = a[n - 1];
        for (int j = 0; j < k; j++)
        {
            sum += a[n - j - 2];
        }
        if (!k)
        {
            b[i] = sum - a[0];
        }
        else
        {
            b[i] = sum;
        }
        /* 计算部分 */
    }
    for (int i = 0; i < t; i++)
    {
        printf("%lld\n", b[i]);
    }
    /* 输出部分 */
    return 0;
}

第十题

最后是啥呢11

问题
「融合」是《游戏王》集换式卡牌游戏中的一张通常魔法卡,是最早对融合怪兽进行融合召唤的魔法卡,也是进行融合召唤的泛用魔法卡。
​现在zwt也想练习一下融合,他的目标转向了数组
每次zwt可以选择两个不同的数字,并且大喊一声“フュージョン!!!”,然后这两个数字就会融合,变成他们和的一半(向上取整)放到数组里
现在有一个序列1,2,3,4,………,n,zwt想知道他要施法几次,每一步选择哪几个数字,这个数组才能变成一个数,并且使得这个最后留下的数字最小
​如n=4,
​1.选择a=2,b=3,数组变为[1,3,3]
​2.选择a=3,b=3,数组变为[1,3]
​3.选择a=1,b=3,数组变为[2]
​如果有多种方案,输出任意一种

Input
第一行输入位t[1,1000],表示有t组数据
每组数据的第一行为n[2,200000]
n的总和不会超过200000

Output
对于每组数据输出最后留下的最小的那个数字
之后n-1行依次输出步骤

Sample Input
1
4

Sample Output
2
2 4
3 3
3 1

分析

从大到小选择两个数,并按规则计算,最后答案恒为2。

解答
#include <stdio.h>
int a[1000];
int c[2000000];
int main(void)
{
    int n;

    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < n; i++)
    {
        int b = a[i];
        for (int j = 0; j < b; j++)
        {
            c[j] = j + 1;
        }
        printf("2\n");
        for (int j = 0; j < b - 1; j++)
        {
            printf("%d %d\n", c[b - j - 2], c[b - j - 1]);
            c[b - j - 2] = (c[b - j - 2] + c[b - j - 1]) / 2 + (c[b - j - 2] + c[b - j - 1]) % 2;
        }
    }
    return 0;
}

  1. 本人编程萌新,解法仅供参考。题目来源见注解 。 ↩︎

  2. HDU-2097 ↩︎

  3. HDU-2098 ↩︎

  4. HDU-6702 ↩︎

  5. 计蒜客-30990 ↩︎

  6. HDU-2040 ↩︎

  7. HDU-1846 ↩︎

  8. HDU-2084 ↩︎

  9. CodeForces-1430A ↩︎

  10. CodeForces-1430B ↩︎

  11. CodeForces-1430C ↩︎

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值