题解 | 算法竞赛团队培训第一次考核

A.小红的签到题

解析

题目描述了一个情景,其中 ( a ) 是题目的总数,( b ) 是参赛人数,而 ( c ) 是所有人通过题目的总数。要找出最多有多少人“ak”,即通过了所有题目。

在这种情况下,如果每个人至少通过了一道题,那么最多可以通过 ( a * b ) 道题。但题目只告诉我们总共通过了 ( c ) 道题。所以,要找出最多有多少人通过了所有题目,我们可以将 ( c ) 除以 ( a ),因为每个人要“ak”就需要通过 ( a ) 道题。

为什么不需要计算余数呢?因为题目问的是最多有多少人“ak”,这意味着我们是在寻找一个整数解,即最多有多少完整地通过了所有题目的人。如果 ( c ) 不能被 ( a ) 整除,那么就意味着不可能有更多的人完全通过所有题目,因为余数代表的是不足以构成一个完整“ak”的人数。

例如,如果 ( c = 123 ) 且 ( a = 6 ),那么 ( 123 / 6 = 20 ) 余 3。这表示最多有 20 个人可以完全通过所有题目,因为剩下的 3 道题不足以让更多的人完成“ak”。

因此,直接用 ( c ) 除以 ( a ) 得到的整数部分就是答案。

Code

#include<iostream>
using namespace std;
int main(){
	int a,b,c;
	cin>>a>>b>>c;
	cout<<c/a<<endl;
	return 0;
}
a,b,c=map(int,input().split())
print(int(c/a))

B.判断闰年

解析

公历闰年的简单计算方法(符合以下条件之一的年份即为闰年):

1.能被4整除而不能被100整除

2.能被400整除

Code

#include<iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	if((n%4==0 && n%100!=0) || (n%400==0)){
		cout<<"yes"<<endl;
	}
	else{
		cout<<"no"<<endl;
	}
	return 0;
}
n=int(input())
if(((n%4==0) and (n%100!=0)) or (n%400==0)):
    print("yes")
else:
    print("no")

C.[NOIP2010]数字统计

解析

见代码

Code

#include <bits/stdc++.h>
using namespace std;

int main() {
	int L, R;
	cin >> L >> R;
	int countTwos = 0;  // 重命名变量以避免冲突
	
	for (int i = L; i <= R; ++i) {
		string num_str = to_string(i);
		countTwos += count(num_str.begin(), num_str.end(), '2');  
	}
	
	cout << countTwos << endl;
	return 0;
}

L,R=map(int,input().split())
count=0
for i in range(L,R+1):
    count+=str(i).count("2")
print(count)

D.[ NOIP2017]图书管理员

解析

见代码

Code

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

int find(const vector<int>& library, const pair<int, string>& tupleX) {
    for (int i : library) {
        string num_str = to_string(i);
        if (num_str.length() >= tupleX.second.length()) {
            string suffix = num_str.substr(num_str.length() - tupleX.first);
            if (suffix == tupleX.second) {
                return i;
            }
        }
    }
    return -1;
}

int main() {
    int n, q;
    cin >> n >> q;
    
    vector<int> library(n);
    for (int i = 0; i < n; ++i) {
        cin >> library[i];
    }
    
    vector<pair<int, string>> needed(q);
    for (int i = 0; i < q; ++i) {
        int x;
        string s;
        cin >> x >> s;
        needed[i] = make_pair(x, s);
    }
    
    sort(library.begin(), library.end());
    
    for (const auto& i : needed) {
        cout << find(library, i) << endl;
    }
    
    return 0;
}

n,q=map(int,input().split())
library=[int(input()) for _ in range(n)]
#和下面代码是一个意思:
# for _ in range(n):
#     library.append(int(input()))
needed=[tuple(map(int,input().split())) for _ in range(q)]
#和下面代码是一个意思:
# for _ in range(q):
#     needed.append(tuple(map(int,input().split())))
#test:
# print(library)
# print(needed)
library.sort()
def find(tupleX):
    for i in library:
        a=-tupleX[0]
        if str(i)[a:]==str(tupleX[1]):
            return i
    return -1
for i in needed:
    print(find(i))

E.最大公约数(lcm)

解析

辗转相除法求最大公因数:

#include <iostream>
using namespace std;
int gcd(int a, int b)
{
    if (a % b==0) return b;
    else return gcd(b, a % b);
}
int x, y; 
int main(){
	
	cin >> x >> y;
	cout << gcd(x, y);
	
	return 0;
}
def gcd(m,n):
    while m%n != 0:
        oldm = m
        oldn = n

        m = oldn
        n = oldm%oldn
    return n

最小公倍数(LCM)等于两个数的乘积除以它们的最大公因数(GCD)

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	unsigned long long a,b;
    cin>>a>>b;
    cout<<lcm(a,b);
    return 0;
}
import math
a,b=map(int,input().split())
print(math.lcm(a,b))

F. 简单的整除

解析

见代码

Code

#include <iostream>
#include <vector>
using namespace std;
int main() {
	int x;
	cin >> x;
	vector<int> li = {2, 3, 5, 7};
	
	for (int i : li) {
		if (x % i == 0) {
			cout << "YES" << endl;
			break;
		}
	}
	if (x % 2 != 0 && x % 3 != 0 && x % 5 != 0 && x % 7 != 0) {
		cout << "NO" << endl;
	}
	
	return 0;
}

x=int(input())
li=[2,3,5,7]
for i in li:
    if x%i==0:
        print("YES")
        break
else:
    print("NO")

I.悬崖

题目

小沙被困在两个巨大的墙壁之中快要被压死了,但是两个墙壁中间就是万丈悬崖,小沙想要多活一会,他脚底下有一个非常强大的弹跳鞋,每一次跳跃可以使他向着对面的墙壁飞行x米,但是他必须要踩上墙壁才能进行下一次跳跃,现已知两个墙壁中间间隔n米,并且每次跳跃两个墙壁之间的距离会减少1米,也就是说小沙在n秒后就会被压死,如果不考虑跳跃期间墙壁的移动,请问小沙最多能跳(飞)多少米。

两面墙壁都没有什么物品可以让小沙能够抓住从而挂在墙壁上,所以小沙要保证一直的跳跃才能不摔下悬崖

说明:小沙第一次跳跃两米,到对面墙壁,然后两个墙壁的距离变成1米,小沙继续跳到对面墙壁(此时虽然两个墙壁之间只有1米,但是小沙还是可以跳跃两米)例如:

img

可以看到虽然墙壁之间的距离只有一米,但是小沙还是可以跳两米远

Code

牛客513205243号 提交的代码

#include<iostream>
using namespace std;
int main(){
	long long x, n;
	cin >> x >> n;
	if(x>=n)
		cout << n * x;
	else 
		cout << x ;
	return 0;
}

砍个价沈 提交的代码

x,n=map(int,input().split())
if x>=n:
    print(int(x*n))
else:
    print(int(x))

J. 猜拳游戏

题目

你正在与长途玩石头剪刀布的猜拳游戏。

请回忆石头剪刀布的游戏规则:两个人同时伸出手,分别出示石头(用 shitou 表示)、剪刀(用 jiandao 表示)或布(用 bu 表示)的手势。石头胜剪刀,剪刀胜布,布胜石头。如果两个人出示的手势相同,则是平局,需要重新进行游戏。

在开始游戏之前,长途会告诉你他要出石头、剪刀还是布。

然而实际上,长途是在欺骗你。他认为你会相信他的话,并且认为你一定会根据他说的话选择能战胜他的手势(例如,他说他会出石头,他便认为你会出布)。

所以最终,长途不会按照他告诉你的手势出拳,而是选择自己所认为一定能战胜你的手势。

现在你已经看透了他的小心思。请问,在知道他告诉你他要出什么手势的情况下,你应该出什么手势才能取胜?

Code

牛客513205243号 提交的代码

#include<stdio.h>
int main(){
	char n[100];
	scanf("%s",&n);
	printf("%s",n);
	return 0;
}

砍个价沈 提交的代码

i=str(input())
if i=="shitou":
    print("shitou")
elif i=="jiandao":
    print("jiandao")
else:
    print("bu")
print(input())

G.小苯的石子游戏

解析

博弈的定义:

博弈的基本要素包括参与人(players)、行动(actions)、信息(information)、策略(strategies)、收益(payoffs)和均衡(equilibria)。

标准表达式(normal form):

设在有 ( ) 个参与者的博弈中,令 ( ) 表示参与者 ( ) 可选择的战略集合(战略空间),其中任意一个特定的战略用 ( ) 表示()。当每个参与者都选定一个策略后,形成了博弈的一个战略组合 ( (s_1, s_2, \ldots, s_n) )。令 ( ) 表示第 ( ) 个参与者选择对应策略后的收益函数。由此可定义博弈的标准表达式:( )。

收益矩阵:

两人博弈的标准表达式通常可以使用收益矩阵来表示。例如,经典的囚徒困境问题。两个犯罪嫌疑人被逮捕并被分别隔离审问,他们不同的行动将带来不同的后果。如果两人都不坦白(沉默),将被判入狱1个月;如果双方都坦白(招认),两人都将判处6个月;如果一人招认而另一人拒不坦白,则招认一方将马上释放,而不坦白的另一人将判处9个月。两人博弈的收益矩阵可表示为如下形式,其中每一单元格有两个数字,分别表示囚徒1和囚徒2的收益: 囚徒困境

策略:

参与人关于其行动的完备集合,即考虑每一种可预见情况下选择的行动,即使那种情况出现不一定会出现。例如,如果参与人在1989年自杀,他的策略里也应当包括如果他在1990年还活着应该采取的对应行动。 策略和行动是有区别的,而在一些简单的博弈中,两者的表现可能是一致的,如上述的囚徒困境中博弈双方的策略和行动可选集都是 ()。

均衡:

由博弈中的 ( n ) 个参与人选取的最佳策略所组成的一个策略组合 ( )。

巴什博弈(Bash Game):

个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取 个( )。最后取光者得胜。 分析: 显然,如果 ( ),那么由于一次最多只能取 ( ) 个物品,所以无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,故后者必然取胜。根据这样的规律,我们发现了如何取胜的法则。 如果 ( ) r 为任意自然数,( ),那么先取者首先拿走 ( ) 个物品,接下来若后取者拿走 ( )(( ))个,那么先取者再拿走 ( ) 个,结果剩下 ( ) 个,以后都保持这样的取法,那么后取者最终会面临 ( ) 的局面,而先取者则必然获胜。总之,要保持给对手留下 ( ) 的倍数,最后就一定能获胜。

Code

#include<bits/stdc++.h>
using namespace std;
void solve() {
	int n;
	cin >> n;
	vector<int> a(n + 1);
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	} 
	// sort(a.begin() + 1, a.end()); // 题目已经保证a有序,可以不写这句
	int s1 = 0, s2 = 0;
	int f = 0;
	for(int i = n; i; i--) {
		if(!f) s1 += a[i];
		else s2 += a[i];
		f ^= 1;
	}
	if(s1 > s2) {
		cout << "Alice" << endl;
	}
	else {
		cout << "Bob" << endl;
	}
}
t=int(input())
for _ in range(t):
    n=int(input())
    a=list(map(int,input().split()))
    #player=["Alice","Bob"]
    player=[0,0]
    count=0
    while a!=[]:
        player[count%2]+=a.pop(-1)
        count+=1
    if player[0]>player[1]:
        print("Alice")
    else:
        print("Bob")

H.小红勇闯地下城

解析

【【算法】最短路径查找—Dijkstra算法】 https://www.bilibili.com/video/BV1zz4y1m7Nq/?share_source=copy_web&vd_source=440c7ec5d64e62c0d02675282b15de02

Code

#include <bits/stdc++.h>
#define int long long //将所有的int替换成long long 防止爆
using namespace std;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int dx[] = {0, -1, 0, 1}, dy[] = {1, 0, -1, 0};
void dijkstra(int n, int m, int u, int v, vector<string> &mp, vector< vector<int> > &d, vector< vector<bool> > &st) // 对地图跑dijkstra算法 
{
    priority_queue<array<int, 3>, vector<array<int, 3>>, greater<array<int, 3>>> q; // 存储三个变量的优先队列 
    q.push({0, u, v}); 
    // 第一个表示(u, v)到当前位置的当前最短距离为 0 
    // 第二个和第三个变量表示当前位置的行和列
    // 从(u, v)开始遍历地图 
    st[u][v] = true; // 将(u, v)标记为已来过 
    d[u][v] = 0; // (u, v)到(u, v)的最短距离为 0 
    while(q.size()) // 如果优先队列不为空 
    {
        auto [dis, x, y] = q.top(); // 取出队头 
        q.pop(); // 弹出队头 
        for(int i = 0; i < 4; i++) // 移动 
        {
            int tx = x + dx[i], ty = y + dy[i]; // 移动后的位置 
            if(tx >= 0 && tx < n && ty >= 0 && ty < m && !st[tx][ty]) // 移动后的位置没来过且合法 
            {
                st[tx][ty] = true; // 将移动后的位置标记为已来过 
                d[tx][ty] = min(d[tx][ty], d[x][y] + (mp[tx][ty] - '0')); // 更新最短距离 
                q.push({d[tx][ty], tx, ty}); // 加入优先队列 
            }
        }
    }
}
void solve()
{
	int q;
    cin >> q;
    while(q--)
    {
        int n, m, h;
        cin >> n >> m >> h;
        vector<string> mp(n); // 存储地图 
        vector< vector<int> > d(n, vector<int>(m, INF)); // 记录从(u, v)到(i, j)的最短距离 
        vector< vector<bool> > st(n, vector<bool>(m, false)); // 标记当前位置有没有来过 
        for(int i = 0; i < n; i++) // 读入地图 
            cin >> mp[i];
        int u, v, x, y;
        for(int i = 0; i < n; i++) // 找到起点和终点 
        {
            for(int j = 0; j < m; j++)
            {
                if(mp[i][j] == 'S') // S 为起点 
                {
                    u = i;
                    v = j;
                    mp[i][j] = '0'; // 起点没有怪,故此处为 0 
                }
                if(mp[i][j] == 'T') // T 为终点 
                {
                    x = i;
                    y = j;
                    mp[i][j] = '0'; // 终点没有怪,故此处为 0 
                }
            }
        }
        dijkstra(n, m, u, v, mp, d, st); // 跑一遍最短路 
        // 如果最低血量消耗 大于等于 已有血量,则无法安全到达终点 
        if(d[x][y] >= h) cout << "No" << endl;
        else cout << "Yes" << endl;
    }
}
signed main()
{
	int T = 1;
//	cin >> T; // 根据具体情况注释 
	while(T--)
		solve();
	return 0;
}
import heapq
from typing import List, Tuple

# 定义方向数组
dx = [0, -1, 0, 1]
dy = [1, 0, -1, 0]


# Dijkstra算法实现
def dijkstra(n, m, u, v, mp, d, st):
    # 使用heapq作为优先队列
    q = []
    heapq.heappush(q, (0, u, v))  # 初始节点的距离是0
    st[u][v] = True
    d[u][v] = 0

    while q:
        dis, x, y = heapq.heappop(q)
        for i in range(4):
            tx, ty = x + dx[i], y + dy[i]
            if 0 <= tx < n and 0 <= ty < m and not st[tx][ty]:
                st[tx][ty] = True
                new_dis = d[x][y] + (int(mp[tx][ty]) - int('0'))
                if new_dis < d[tx][ty]:
                    d[tx][ty] = new_dis
                    heapq.heappush(q, (new_dis, tx, ty))


# 主解决问题函数
def solve():
    q = int(input())
    for _ in range(q):
        n, m, h = map(int, input().split())
        mp = [input() for _ in range(n)]
        d = [[float('inf')] * m for _ in range(n)]
        st = [[False] * m for _ in range(n)]

        u, v, x, y = None, None, None, None
        for i in range(n):
            for j in range(m):
                if mp[i][j] == 'S':
                    u, v = i, j
                    mp[i] = mp[i][:j] + '0' + mp[i][j + 1:]  # 将起点标记为'0'
                elif mp[i][j] == 'T':
                    x, y = i, j
                    mp[i] = mp[i][:j] + '0' + mp[i][j + 1:]  # 将终点标记为'0'

        dijkstra(n, m, u, v, mp, d, st)
        if d[x][y] >= h:
            print("No")
        else:
            print("Yes")


# 主函数入口
if __name__ == "__main__":
    T = 1
    # T = int(input())  # 如果需要处理多个测试用例,可以取消注释此行
    for _ in range(T):
        solve()