第六届传智杯程序设计挑战赛(校赛初赛)

题目

第一题

键盘输入两个字符串,将这两个字符串进行拼接后输出。

输入描述

键盘输入两个字符串

输出描述

输出两个字符串拼接后的结果

例式1:

输入:

hello

nihao

输出:

hellonihao

解题思路

这个问题的解题思路非常简单,主要涉及两个步骤:

一是从键盘输入两个字符串。

二是将这两个字符串进行拼接。

以下是相应的解题思路的伪代码:

1. 从键盘输入字符串 str1

2. 从键盘输入字符串 str2

3. 将 str2 拼接到 str1 的后面,得到拼接后的字符串 result

4. 输出 result

 

同时也要确保你的输入符合题目的要求,并且程序的输出是正确的。如果在特定的在线评测系统中遇到问题,还需要确保你的程序满足该评测系统的输入输出规范。

代码如下:

#include <iostream>
#include <string>

int main() {
    // 声明两个字符串变量
    std::string str1, str2;

    // 从键盘输入两个字符串
    std::getline(std::cin, str1);
    std::getline(std::cin, str2);

    // 在两个字符串之间添加一个空格,并将它们进行拼接
    std::string result = str1 + str2;

    // 输出拼接后的结果
    std::cout << result;

    return 0;
}

 

第二题

擂台赛要开始了,现在有n名战士,其中第名战士的战斗力为a。现在准备从这些战士中挑两名战士进入擂台赛进行对战,由于观众们更喜欢看势均力敌的比赛,所以我们也要挑选两个战斗力尽可能相近的战士进行参赛。那么现在请问,战斗力最接近的两名战士,战斗力之差为多少?

 

输入:

第一行输入一行一个正整数n表示战士的数量

第二行输入 n 个正整数表示每名战上的战斗力。(1<=n<=10^5 ,1<=ai<=10^9)

输出描述

输出一行一个正整数表示答案

例1

输入

3

355

 

输出

0

 

说明

选择两名战斗力为 5 的战士,战斗力之差为 0

示例2

输入

5

1 10 4 9 6

 

输出

1

 

说明

选择战斗力为 10 和9 两名战上,战斗力的差值为 1

 

解题思路

这个问题的解题思路是先对战士的战斗力进行排序,然后遍历排序后的列表,找到相邻两个战士战斗力之差的最小值。以下是详细的解题步骤:

读取输入,获取战士的数量 n 和每名战士的战斗力列表。

对战斗力列表进行排序,这样相邻的战士战斗力就会挨在一起。

初始化一个变量 min_difference 为正无穷大,用来记录最小的战斗力差值。

遍历排序后的战士列表,计算相邻两个战士的战斗力差值,并更新 min_difference。

输出最终的 min_difference。

通过这种方式,你能够找到两名战士战斗力之差的最小值,从而满足观众更喜欢看到势均力敌的比赛的要求。

 

代码:

#include <iostream>

#include <vector>

#include <algorithm>

#include <climits>

 

using namespace std;

 

int main() {

    int n;

    cin >> n;

 

    vector<int> powers(n);

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

        cin >> powers[i];

    }

 

    sort(powers.begin(), powers.end());

 

    int min_difference = INT_MAX;

 

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

        int difference = powers[i] - powers[i - 1];

        min_difference = min(min_difference, difference);

    }

 

    cout << min_difference << endl;

 

    return 0;

}

 

第三题-红色和紫色-【第六届传智杯程序设计挑战赛解题分析详解复盘】(Java&Python&C++实现)

漫长的生命总是无聊的。这天,小红和紫准备玩一个染色游戏。

她们拿出了一个有 n* m 个格了的网格,每个格了只能被染成红色或紫色。每个人可以任意选择一个格了染成红色和紫色,两人轮流进行染色。

她们约定,不能有两个相邻的格子有相同的颜色。最后无法进行染色的人判输

小红先手进行染色。小红想知道,双方都采用最优策略的情况下,她能否取得胜利?

 

输入描述

 

两个正整数n和m,用空格隔开(1<= n, m <=10^9)

 

输出描述

 

如果小红获胜,则输出一个字符串"akai"

 

如果紫获胜,则输出一个字符串"yukari"

例1

输入

 

1 1

 

输出

 

akai

 

说明

小红直接把这个格子染成红色,即可获胜

示例2

输入

 

1 2

 

输出

 

yukari

 

说明

小红染色后,紫只需要在相邻的格子染上不同的颜色即可获胜

 

解题思路

首先,让我们分析一下这个游戏。两个玩家轮流在网格上染色,不能让相邻的格子具有相同的颜色,最后无法进行染色的一方判输。

 

关键观察点:

 

如果网格的行数和列数都是偶数,那么紫色方可以始终保持与红色相邻的颜色。这是因为如果红色方在某一行或某一列染色,紫色方总是可以选择相邻的行或列进行染色,使得相邻格子颜色不同,从而保持胜利。

如果网格的行数和列数有一个是奇数,那么红色方可以通过染色使得最后一行或最后一列只有一个格子。这是因为无论紫色方如何染色,红色方都可以选择染色使得最后一行或最后一列只有一个格子,从而获得胜利。

基于上述观察,我们可以得出判断胜负的规律,即:

 

如果网格的行数和列数都是偶数,紫色方获胜。

如果网格的行数和列数有一个是奇数,红色方获胜。

根据这个规律,可以编写上述修正后的代码。这个代码适用于判断胜负的情况,并考虑了双方采用最优策略的情况。

代码:

#include <iostream>

 

std::string game_winner(int n, int m) {

    if ((n * m) % 2 == 0) {

        return "yukari";

    } else {

        return "akai";

    }

}

 

int main() {

    int n, m;

    std::cin >> n >> m;

 

    // 输出结果

    std::cout << game_winner(n, m) << std::endl;

 

    return 0;

}

第四题-abb 【第六届传智杯程序设计挑战赛解题分析详解复盘】(Java&Python&C++实现)

leafee 最近爱上了 abb 型语句,比如“叠词词”、“恶心心”leafee 拿到了一个只含有小写字母的字符串,她想知道有多少个"abb"型的子序列?

 

定义: abb 型字符串满足以下条件:

 

1.字符串长度为 3

 

2.字符串后两位相同

 

3.字符串前两位不同

 

输入描述

 

第一行一个正整数n 第二行一个长度为 n的字符串 (只包含小写字母)

 

1<n<10^5

 

输出描述

 

"abb"型的子序列个数

 

例1

 

输入

 

6 abcbcc

 

输出

 

8

 

说明

 

共有1个abb,3个acc,4个bcc

 

示例2

 

输入

 

4

 

abbb

 

输出 3

 

解题思路

这道题的解题思路主要涉及到计算以字符串中每个字符为开头的 “abb” 型子序列的个数。具体来说,我们需要对字符串进行遍历,对于每个字符,统计该字符之后的两个字符中,有多少个与它们不同的字符。根据这个统计信息,我们可以计算以当前字符为开头的 “abb” 型子序列的个数。

 

以下是解题思路的详细步骤:

 

使用一个数组 ch 统计字符串中每个字符的出现次数。

初始化一个累加变量 total_sum 为 0,用于存储最终的结果。

遍历字符串,对于每个字符,执行以下步骤:

a. 将当前字符出现次数减一,表示不再考虑当前字符。

b. 对于剩余的字符,统计与当前字符不同的字符的个数,然后根据组合公式计算以当前字符为开头的 “abb” 型子序列的个数,将结果累加到 total_sum 中。

输出最终结果 total_sum。

这个思路的关键在于理解 “abb” 型子序列的定义,以及通过对每个字符的处理来计算满足条件的子序列个数。希望这样的解释能够帮助你更好地理解这道题目。

#include <iostream>

#include <vector>

 

using namespace std;

 

int main() {

    int n;

    cin >> n;

 

    if (n < 3) {

        cout << 0 << endl;

        return 0;

    }

 

    string s;

    cin >> s;

 

    long long total_sum = 0;

    vector<long long> dp(n, 0);

    vector<int> ch(26, 0);

 

    for (char c : s) {

        ch[c - 'a']++;

    }

 

    for (int i = 0; i < n - 2; i++) {

        ch[s[i] - 'a']--;

        for (int j = 0; j < 26; j++) {

            if (s[i] - 'a' != j) {

                dp[i] += ch[j] * (ch[j] - 1) / 2;

            }

        }

    }

 

    for (int i = 0; i < n - 2; i++) {

        total_sum += dp[i];

    }

 

    cout << total_sum << endl;

 

    return 0;

}

第五题-kotori和素因子【第六届传智杯程序设计挑战赛解题分析详解复盘】(Java&Python&C++实现)

kotori拿到了一些正整数。她决定从每个正整数取出一个素因子。但是,kotori有强迫症,她不允许两不同的正整数取出相同的素因子。她想知道,最终所有取出的数的和的最小值是多少?

 

注:

 

若a%k==0,则称k是a的因子。

 

若一个数有且仅有两个因子,则称其是素数。显然1只有一个因子,不是素数。

 

输入描述

 

第一行一个正整数n,代表kotori拿到正整数的个数 第二行共有n个数ai,表示每个正整数的值 保证不存在两个相等的正整数。

 

1<=n<=10 2<=ai<=1000

 

输出描述

 

1个正整数,代表取出的素因子之和的最小值。若不存在合法的取法,则输出-1。

 

例1

 

输入

 

4 12 15 28 22

 

输出

 

17

 

说明

 

分别取3,5,7,2,可保证取出的数之和最小 例2 输入 5 4 5 6 7 8 输出 -1 备注 1<=n<=10 2<=ai<=1000

 

解题思路

这道题的解题思路基于以下几个关键点:

 

找到每个数的素因子: 对于每个给定的正整数,需要找到它的素因子。在代码中,通过遍历从 2 到该数本身的所有数,找出其中是素数的因子。

 

素数判断: 在代码中,使用了一个 isPrime 函数来判断一个数是否为素数。这个函数会检查一个数是否大于等于2,并且是否能被2到根号n之间的任何整数整除。如果能被整除,那么它不是素数。

 

深度优先搜索(DFS): 通过深度优先搜索来尝试不同的素因子组合,找到和的最小值。在DFS的过程中,需要注意每个素因子只能被选择一次,因此需要使用一个数组 vis 来标记素因子是否已经被选择。

 

初始化素数数组: 在代码中,使用 init 函数初始化了一个素数数组,用于在找素因子时进行快速判断。

 

结果输出: 最后,输出所有素因子和的最小值。如果不存在合法的取法,则输出-1。

 

这个问题的本质是一个组合优化问题,通过DFS搜索所有可能的组合,找到使得素因子和最小的情况。这种类型的问题通常可以使用回溯法,深度优先搜索等方法来解决。

#include <bits/stdc++.h>

using namespace std;

int n;

int vis[1005];

vector<int> v[105];

int ans=999999;

const int MAX = 1000005;

bool prime[MAX];

void init() {

 memset(prime,true,sizeof prime);

 for(int i=2; i*i<MAX; i++) {

  if(prime[i]) {//是素数 

   for(int j=i*2; j<MAX; j+=i)//从2倍开始,n倍 

    prime[j]=false;//各个倍数 

  }

 }

void dfs(int d,int sum){

 if(d==n){

  ans=min(ans,sum);

  return ;

 }

 for(int i=0;i<v[d].size();i++){

  if(!vis[v[d][i]]){

   vis[v[d][i]]=1;

   dfs(d+1,sum+v[d][i]);

      vis[v[d][i]]=0;

  }

 }

}

int main(){

 init();

 scanf("%d",&n);

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

  int temp;

  scanf("%d",&temp);

  for(int j=2;j<=temp;j++){

   if(temp%j==0&&prime[j]){

    v[i].push_back(j);

    //cout<<j<<" ";

   }

  }

  //cout<<endl;

 }

 dfs(0,0);

 if(ans==999999)

     printf("-1\n");

 else

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

 return 0;

}

第六题-红和蓝【第六届传智杯程序设计挑战赛解题分析详解复盘】(Java&Python&C++实现)

你拿到了一棵树,请你给每个顶点染成红色或蓝色。

 

要求: 每个红点周围有且仅有一个红点,每个蓝点周围有且仅有一个蓝点。

周围”的定义:某点周围的点指通过邻边直接连接的点所谓树,即没有自环、重边和回路的无向连通图。

输入描述

第一行一个正整数n,代表树的顶点个数.(1<n<100000)

 

接下来的n-1行,每行两个正整数u和v,代表点u 和点v有一条边连接。 (1<=u,v<=n)保证输入的一定是一棵合法的树。

输出描述

如果可以达成染色的要求,请输出一个长度为 n 的字符串,第i个字符代表第i个顶点的染色情况,B 代表蓝色,R代表红色(若有多种合法染色的方法,输出任意1种即可)

 

否则直接输出-1

例示1:

 

输入:

 

4

 

1 2

 

2 3

 

3 4

 

输出:

 

RRBB

 

说明:

 

1为红点,它连接的边有只有一个红点: 2

 

2为红点,它连接的边有只有一个红点: 1

 

3为蓝点,它连接的边有只有一个蓝点: 4

4为蓝点,它连接的边有只有一个蓝点: 3

 

示例2:

输入

 

4

 

1 2

 

1 3

 

1 4

 

输出

 

-1

 

说明:

 

可以证明,无论怎么染色,都无法满足题目的要求。

 

解题思路

这个问题是一个树的染色问题,要求每个顶点染成红色或蓝色,并且满足以下条件:

 

每个红点周围有且仅有一个红点。

每个蓝点周围有且仅有一个蓝点。

解题思路主要分为两步:

 

第一次深度优先搜索(DFS):遍历树,标记每个节点的标记信息(dp数组),并检查是否有孤立的节点。孤立的节点意味着无法满足染色条件。

第二次DFS:根据第一次DFS的标记信息,确定每个节点的颜色。

具体的步骤如下:

 

使用邻接表表示树的结构,构建一个图。

第一次DFS:从根节点开始遍历整个树,标记每个节点的标记信息(dp数组)。如果发现孤立的节点或者某个节点被多次标记,说明无法满足染色条件,输出-1。

第二次DFS:根据第一次DFS得到的标记信息,确定每个节点的颜色,使得满足染色条件。

这类问题的关键在于通过深度优先搜索(DFS)遍历整个树,同时根据问题要求进行合理的标记和操作。

#include <stdio.h>

#include <string.h>

 

int mark = 0; //标记同色的父子节点

int head[100010]; // 存储树的索引节点

struct ty {

    int value; // 边的值

    int next; // 相邻边的索引

} edge[200010];

 

int dp[100010] = {0}; // 第一次DFS时,每个点的标记信息

int color[100010] = {0}; // 第二次DFS时,记录每个节点的颜色信息

 

/* 添加新的边到树型结构中 */

void addedge(int x, int y, int pos) {

    edge[pos].value = y;

    edge[pos].next = head[x];

    head[x] = pos;

}

 

int dfs1(int x, int father) {

    int son = 0;

    for (int i = head[x]; i != -1; i = edge[i].next) {

        if (edge[i].value != father) { // 避免回环

            ++son;

            if (dfs1(edge[i].value, x)) return 1;

        }

    }

    // son==0表示叶子节点 ; dp[x]==0 表示 x 这个点未被标记

    if (son == 0 || dp[x] == 0) {

        if (dp[father] != 0) return 1; // 一个节点被多次标记,无解

        dp[x] = dp[father] = ++mark;

    }

    return 0;

}

 

void dfs2(int x, int father) {

    for (int i = head[x]; i != -1; i = edge[i].next) {

        if (edge[i].value != father) { // 避免回环

            if (dp[edge[i].value] == dp[x])

                color[edge[i].value] = color[x]; // 两个节点标记相同,则颜色相同

            else

                color[edge[i].value] = !color[x]; // 两个节点标记不同,则颜色不同

            dfs2(edge[i].value, x);

        }

    }

}

 

int main() {

    int x, y, n, pos = 1;

    scanf("%d", &n);

    memset(head, -1, sizeof(head));

    memset(edge, -1, sizeof(edge));

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

        scanf("%d%d", &x, &y);

        addedge(x, y, pos);

        ++pos;

        addedge(y, x, pos);

        ++pos;

    }

 

    // 1==dfs1(1,0) 表示无解

    // dp[0] 其实是整个树的第一个节点的根节点,上面的code中,我们的树是从pos==1开始的

    // 也就是第一个节点的标记信息在dp[1]中,这里使用dp[0]就是为了观察第一个节点(dp[1])有没有被孤立

    // 如果孤立了则dp[0]一定被标记了,反之dp[0]一定为0

    if (dfs1(1, 0) || dp[0]) {

        printf("-1");

        return 0;

    }

    color[1] = 1; // 这里也可以是0,题目也说了可能多解

    dfs2(1, 0);

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

        printf("%c", color[i] ? 'R' : 'B');

    }

 

    return 0;

}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值