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的主要内容,如果未能解决你的问题,请参考以下文章