2021.5.14 2022蓝桥杯练习赛2

Posted 斗奋力努

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021.5.14 2022蓝桥杯练习赛2相关的知识,希望对你有一定的参考价值。

2021.5.14 2022蓝桥杯练习赛2

闲话:
1、就难度而言,练习赛2较练习赛1有了一定的提高,可能开始会有点不太自信,但这是属于正常现象,多练就会做了。
2、就体验而言,这场练习赛有一两个题需要认真读题,题目没有想的那么简单,还是有一定思考和有一点小坑的
3、没什么,昨天是2021年5月13号,需要记住的日子。

题目
1、试题 算法训练 筛选号码在这里插入图片描述
解析:本题真的是一道在经典不过的题目了,解题是应该要看一眼就知道这是裸的约瑟夫环问题,直接上公式就可以了。当然厉害一点的也可以去模拟这个过程,数据n<10000应该也是可以的。

公式:s=(s+m)%i; (s为值,初始为0,m表示每次从1开始的第m个人出去,记得输出答案是s+1,和for循环从i=2开始)

查漏补缺:约瑟夫环——公式法(递推公式)
推荐这篇博文,当时我也是看的这篇去理解的约瑟夫环问题

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,s=0;
	cin>>n;
	for(int i=2;i<=n;i++)
	{
		s=(s+3)%i;
	}
	cout<<s+1;
}

----------------------------------------------------------------------------------------------

2、试题 算法训练 最大体积
在这里插入图片描述
解析:本题感觉跟完全背包有点像,但在完全背包的基础上有点改动,归结为完全背包的拓展+数学思维。本题虽然数据较小,但我觉得这题还是不能纯暴力乱搞,当然主要是我也不会。
思路:
1、首先我们应该考虑什么情况会使得有无限解。经过我非非非常认真的思考, 我发现,如果所有体积的gcd值不为1的时候,我们可以组成无数多种情况,这样一直组成下去,总会存在比当前认为的最大值更大的数。所以此时就有无限解输出0。(可能是我的LJ编译器不支持gcd和__gcd(a,b)函数同时使用,不然会无法识别我的gcd什么的,所以代码中用变量t记录所有体积的gcd值
2、现在我们知道是有限解了,那么怎么求值可能又是大家遇到的第二个问题。
因为输出最大不可能值,没有其他限制条件,那么直接从大到小遍历vis数组找到第一个vis[i]==0就可以了,下标即答案。
3、怎么给vis数组赋值。这就是完全背包的问题了。上次发了背包九讲问题的学习链接,应该都会完全背包了,这里就不细说了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;   //极限数据 输入 2 491 499 输出 244019
ll n,t;
ll a[15];
bool vis[N];

bool check(){
    for(int i=1;i<=n;i++){
        t=__gcd(t,a[i]);
    }
    return t==1;
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        vis[a[i]]=1;
    }
    if(check()){
        for(int i=1;i<=n;i++){
            for(int j=a[i];j<N;j++){
                vis[j]|=vis[j-a[i]];
            }
        }
        for(int i=N-1;;i--){
            if(!vis[i]){
                cout<<i<<"\\n";
                return 0;
            }
        }
    }
    else puts("0");
}

-----------------------------------------------------------------------------------------------

3、试题 算法提高 笨小猴
在这里插入图片描述
解析:这个题是我这次没有一发ac的题,但这个题是真的是个**题
可以使用map来记录’a’~~'z’中每个字符出现的次数。记得每个字符初始出现的此处都是0,且输入字符串没有某字符时,该字符对应的a[i]值也是0,这一点需要在求最小值的时候特别注意。其他的应该没什么,就是考对使用map的使用。

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
map<int,int>a;
string s;
int maxn=-inf,minn=inf,cha;
int main(){
    cin>>s;
    for(int i=0;i<s.length();i++){
        a[s[i]-'a']++;  //使mp中字符'a'对应数字0,字符'b'对应数字1....字符'z'对应数字25,这样后面遍历顺眼点
    }
    for(int i=0;i<26;i++){
        maxn=max(maxn,a[i]);
        if(a[i]!=0) minn=min(minn,a[i]);  //a[i]值等于0即代表没有出现过该字符,不予考虑
    }
    cha=maxn-minn;
    if(cha==1||cha==0){
        cout<<"No Answer\\n"<<"0";
        return 0;       
    }
    for(int i=2;i<cha;i++){
        if(cha%i==0){
            cout<<"No Answer\\n"<<"0";
            return 0;
        }
    }
    cout<<"Lucky Word\\n"<<cha;
}

-----------------------------------------------------------------------------------------------

4、试题 算法提高 学霸的迷宫
在这里插入图片描述
解析:这类走迷宫问题,百分之九十九会用到bfs算法
这都不能说是算法了,在平常的算法比赛中bfs是一种必备的基础技能,需要掌握。这题是在问 走出迷宫的最短路径长度问题的基础上,加上输出最短路径,其他的都一模一样。
十分巧的是上学期我的一个课设题目就是迷宫问题,且要求跟这个题目大同小异,十分感谢涛哥当时教了我一手,所以这个题基本就被我水过去了。(加粗感谢涛哥)
思路:
1、跟普通的走迷宫问题一样,我利用队列queue的先进先出的特性,来遍历每个到达的点,因为每个节点的信息不只是x,y,还有一个走到的step需要记录,所以这里用pair是不太现实的了,不过没有关系,我可以用struct,这是没得丝毫影响的。当到了点(n,m)时,输出当前step的就是最小步数了。我们就成功解决了第一小问。
2、第二小问是输出路径。这个要求是如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。这个为难了我,平时写dx数组、dy数组的写法,不过这都问题不大,就是看着感觉别扭 。剩下的就是这for循环四个方向的时候,去记录一下该次操作是什么,我这里用cz数组记录的是第几种操作,开始用to数组打表相应操作,最后输出就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m;
char mp[N][N];
bool vis[N][N];
int cz[N][N];
int dx[5]={1,0,0,-1};
int dy[5]={0,-1,1,0};
char to[5]={"DLRU"};
struct node{
    int x,y,step;
};
queue<node>q;

void bfs(){
    q.push({1,1,0});
    vis[1][1]=1;

    while(!q.empty()){
        node t=q.front();
        q.pop();
        if(t.x==n&&t.y==m){
            cout<<t.step<<"\\n";
            return;
        }
        for(int i=0;i<4;i++){
            /*
            这里我们是从队列中读出了队首的结构体单位,当前处在点(t.x,t.y)上,在不管下一个走到的节点是否是合法状态的情况下,
            我们都有这上下左右四种走法。当然实际情况中下一步需要满足合法状态。
            合法状态:1、在这个迷宫里面,即(nx>=1&&nx<=n&&ny>=1&&ny<=m)
                     2、是否可以走,即(mp[nx][ny]=='0')。因为题目限制了mp[nx][ny]=='1'是不可以走的
                     3、是否是第一次走到该点,即(vis[nx][ny]==0)。因为如果不是第一次走到该点,是否意味着我们走了一段环形
                     的路,走完那一圈,我们又回到了该点,这样明显不符合最短路径的情况
            一般处理的方法:从起点走到终点----就是我下面这种
            另类的处理方法:从终点走到起点(????这是什么鬼)----这种基本不会用,因为有的题目并不能保证起点到终点一定有路,
                           这种无解的情况根据不同的题目会有不同的特定输出。这里不用管,因为蓝桥不会这么恶心人(QwQ)
            */
            /*
            首先,我们讲上下左右按照字典序排序好(下左右上--DLRU),当然dx、dy数组也得相应变换。我们从起点到终点,每次都
            将通过cz数组记录好我们走到该后进行下一步的操作是什么,来为后面的Step函数做准备。
            */
            int nx=t.x+dx[i];     
            int ny=t.y+dy[i];
            int nstep=t.step+1;
            if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&mp[nx][ny]=='0'&&!vis[nx][ny]){
                cz[nx][ny]=i;   //注释(1)
                q.push({nx,ny,nstep});
                vis[nx][ny]=1;
            }
        }
    }
}

void Step(int n,int m){    //另类的从终点到起点
    if(n==1&&m==1) return;   //此时我们是不是已经到达了起点,我们就可以结束掉Step函数
    /*
    每一次往回走,就是开始是t.x+dx[i],t.y+dy[i];那么现在就是-dx[i],-dy[i]
    此时减去的cz[n][m]的值,是不是恰好对应了  上面注释(1)记录的第i类变化。
    就这样一直往起点走,到了起点就return,同时每一次Step后后加上输出语句,这里就刚好再次转变成从起点往终点输出了
    */
    Step(n-dx[cz[n][m]],m-dy[cz[n][m]]); 
    cout<<to[cz[n][m]];
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>mp[i][j];
        }
    }
    bfs();
    Step(n,m);
}

在这里插入图片描述

-----------------------------------------------------------------------------------------------

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m;
char mp[N][N];
bool vis[N][N];
int dx[5]={1,0,0,-1};
int dy[5]={0,-1,1,0};
char dpath[5]={'D','L','R','U'};
struct node{
    int x,y,step;
    string path;
};
queue<node>q;

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>mp[i]+1;
    node start;
    start.x=start.y=1;
    start.step=0;
    start.path="";
    q.push(start);
    vis[1][1]=1;
    while(!q.empty()){
        node t=q.front();
        q.pop();
        int nx=t.x,ny=t.y,nstep=t.step;
        if(nx==n&&ny==m){
            cout<<t.step<<"\\n"<<t.path<<"\\n";
            return 0;
        }
        for(int i=0;i<4;i++){
            node tt;
            tt.x=nx+dx[i];
            tt.y=ny+dy[i];
            tt.step=t.step+1;
            tt.path=t.path+dpath[i];
            if(tt.x>=1&&tt.x<=n&&tt.y>=1&&tt.y<=m&&mp[tt.x][tt.y]=='0'&&!vis[tt.x][tt.y]){
                vis[tt.x][tt.y]=1;
                q.push(tt);
            }
        }
    }
}

---------------------------------------------------------------------------------------------------------------

5、试题 算法训练 友好数
在这里插入图片描述
解析:本题应该是本场最简单的题。没有小细节,也没有考算法,唯一考了就是C语言基础。用suma、sumb分别记录a、b除开自身的约数和。然后if(suma==b && sumb == a) 为真就输出yes,否则就输出no。 数据才10000,直接两次for循环解决。

#include<bits/stdc++.h>
using namespace std;
int a,b;
int suma,sumb;

int main(){
    cin>>a>>b;
    for(int i=1;i<a;i++){if(a%i==0) suma+=i;}
    for(int i=1;i<b;i++){if(b%i==0) sumb+=i;}
    if(suma==b&&sumb==a) puts("yes");
    else puts("no");
}

-----------------------------------------------------------------------------------------------

6、试题 算法提高 高精度乘法
在这里插入图片描述
解析:这个题是一个好题,反正我是不太会。
Python在这里插入图片描述
C++(龚神)
在这里插入图片描述
C++(自己)
在这里插入图片描述

Java(队友)
在这里插入图片描述
FFT学习链接
这类高精题我还是挺喜欢用Python的,根据代码长度占用空间来看,很明显的发现码量:Python(40B)<Java(367B)<C++(1.584KB)<C++(1.742KB)。
(龚神的代码还加了一些其他的东西,所以会比我的代码长些,但本质都一样,没有不同。)

可惜我Python学艺不精只a90分;
Java是队友以前帮我写的,就是用Java中的大数,然后就莫名其妙的ac了;
C++是龚神以前帮我写的,当时不会NTT,(现在也不怎么会,但也有了自己的NTT板子,跟巨佬差距还是挺大的)

思路:好好学习,去看看FFT或NTT。平时大家肯定主要都是用C++做题,而且在蓝桥的竞赛中,报名了C/C++组,中途是不能用Java或Python去解题的。所以最好还是要会用C++做题。

这里我仅贴出代码,有兴趣的同学可以课余自己去了解。

Java代码- - -队友的解法

import java.io.*;
import java.math.*;
import java.util.*;
import java.text.*;

public class Main {
	public static void main(String[] args) {
		  Scanner cin = new Scanner (new BufferedInputStream(System.in));
		  BigDecimal a=cin.nextBigDecimal();
		  BigDecimal b=cin.nextBigDecimal();
		  BigDecimal ans=a.multiply(b);
		  System.out.println(ans.toString());
	}

}

-----------------------------------------------------------------------------------------------
C++代码- - -龚神的模板

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+10, P = 998244353, G = 3, Gi = 332748118;

string s;
int cnta, cntb;
int limit = 1, L, rev[MAXN];
long long a[MAXN], b[MAXN];

int cs(long long *A) {
	for(int i = 0;i < s.length(); i++) A[i] = s[i]-'0';
	return (int)s.length();
}

inline long long fastpow(long long a, long long k) {
	long long base = 1;
	while(k) {
		if(k & 1) base = (base * a ) % P;
		a = (a * a)以上是关于2021.5.14 2022蓝桥杯练习赛2的主要内容,如果未能解决你的问题,请参考以下文章

2021.5.22 2022蓝桥杯练习赛3

2021.5.29 2022蓝桥杯练习赛4

PTA2022年蓝桥杯及天梯赛赛前训练(C++练习)

2021.5.7 2022蓝桥杯练习赛1

C++练习2022年蓝桥杯选拔赛

C++练习2022年蓝桥杯第二次选拔赛