第十五届蓝桥杯省赛

第十五届蓝桥杯省赛

1.握手问题

#include <iostream>
using namespace std;
int main()
{
//划分为43,7两组
//(43*42)/2+7*43=28*43
cout<<28*43;
  
  return 0;
}
 
 

2.小球反弹(难)

分析:
当做两个方向往返
代码:
/*
考点:速度分解
分解为x轴往返,y轴往返(回到左上角起点)
假设x轴做了p个往返,y轴做了q个往返,时间为t
速度可以当做是x轴15,y轴17
x轴路程:dx*t=p*2*x       
y轴路程:dy*t=q*2*y
两式相除
dx/dy=p/q*x/y
即(dx*y)/(dy*x)=p/q
可以把分母看作p,分子看作q   (因为不想算除法)
p,q需要约分通过gcd找最大公约数约分
由p求t->t=2px/dx
*/
#include<bits/stdc++.h>
using namespace std;
int gcd(int p,int q){if(q==0){return p;}else{return gcd(q,p%q);}
}
int main(){int x=343720;int y=233333;int dx=15;int dy=17;int p=dx*y;int q=dy*x;int g=gcd(p,q);//g为p,q的最大公约数p=p/g;q=q/g;double t=p*2*x/dx;//时间double s=t*sqrt(15*15+17*17);//总路程printf("%.2f",s);return 0;
}

核心:(dx*y)/(dy*x)=p/q 

需要记忆的模版(最大公约数)gcd

 

int gcd(int p,int q){if(q==0){return p;}else{return gcd(q,p%q);}
}

 3.好数

//考察取每一位
#include<bits/stdc++.h>
using namespace std;
bool good(int a){//如果是好数返回true
int i=0;
while(a!=0){
i++;
int d=a%10;//当前位的数字
if(i%2!=0){//奇数位
if(d%2==0){return false;
}
}
else if(i%2==0){//偶数位
if(d%2!=0){return false;
}}
a/=10;
}
return true;
}
int main(){int n;cin>>n;int cnt=0;for(int i=1;i<=n;i++){
if(good(i)){// cout<<i<<endl;cnt++;
}}// cout<<"------------------------------------------";cout<<cnt;return 0;
}

4.R格式(难)

考点:高精度*低精度

 

答案代码
 /*
分析:
求2^n*d
2的n次方当n为1000时非常大所以要用高精度算法
d很小为低精度
所以本题考:高精度*低精度
高精度可以用数组模拟
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1300;
int a[N];//将字符串每一位转为整型
string s;//存放低精度浮点数
int main(){
int n;
cin>>n>>s;reverse(s.begin(),s.end());//高精度算法因为可能涉及进位,所以先把字符串翻转,则原来的最高位进位变成现在往右增加一位
int pos=s.find('.');//小数点位置
s.erase(pos,1);//删除小数点,因为本题最后四舍五入与小数点无关。从pos开始删一位就是把小数点删除了
int len=s.size();
//字符串转整型
for(int i=0;i<len;i++){a[i+1]=s[i]-'0';
}
//乘n个2
for(int i=0;i<n;i++){//每一位乘2//扫描for(int j=1;j<=len;j++){a[j]*=2;}
//处理进位问题
for(int j=1;j<=len;j++){if(a[j]>=10){a[j+1]++;a[j]%=10;if(j==len){//最高位
len++;}}}
}
//小数点四舍五入
if(a[pos]>=5){a[pos+1]++;//四舍五入后进位问题for(int i=pos+1;i<=len;i++){if(a[i]>=10){a[i+1]++;a[i]%=10;if(i==len){len++;}}}
}
//反着输出
for(int i=len;i>=pos+1;i--){cout<<a[i];
}return 0;
}

 分析代码

 /*
分析:
求2^n*d
2的n次方当n为1000时非常大所以要用高精度算法
d很小为低精度
所以本题考:高精度*低精度
高精度可以用数组模拟
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1300;
int a[N];//将字符串每一位转为整型
string s;//存放低精度浮点数
int main(){
int n;
cin>>n>>s;//s就是d
reverse(s.begin(),s.end());//高精度算法因为可能涉及进位,所以先把字符串翻转,则原来的最高位进位变成现在往右增加一位
//find,erase,size是字符串方法
int pos=s.find('.');//小数点位置
s.erase(pos,1);//删除小数点,因为本题最后四舍五入与小数点无关。从pos开始删一位就是把小数点删除了
int len=s.size();//删完后字符串s长度
//字符串转整型
for(int i=0;i<len;i++){//a数组从下标1开始存放
  a[i+1]=s[i]-'0';//字符串转整型
}
//乘n个2
for(int i=0;i<n;i++){//n个2相乘
  //每一位乘2
  //扫描
  for(int j=1;j<=len;j++){//遍历a
    a[j]*=2;
  }
//处理进位问题
for(int j=1;j<=len;j++){//遍历a
  if(a[j]>=10){
    a[j+1]++;
    a[j]%=10;
 if(j==len){//最高位,并且最高位>=10要进位
len++;
  }
  }
 
}
}
//小数点四舍五入
if(a[pos]>=5){
  a[pos+1]++;
  //四舍五入后进位问题
  for(int i=pos+1;i<=len;i++){
    if(a[i]>=10){
      a[i+1]++;
      a[i]%=10;
      if(i==len){
        len++;
      }
    }
  }
}
//反着输出(从高位->低位输出)
for(int i=len;i>=pos+1;i--){
  cout<<a[i];
}
  return 0;
}
删除小数点后

5.宝石组合(难)

考点:唯一分解定理

代码:

/*
分析:
考点:唯一分解定理
任何一个大于1的自然数,如果他不是质数,那么他可以分解为有限个质数的乘积
例如:A,B为两个大于1的自然数
A=p1^a1*p2^a2*p3^a3*...pn^an
B=p1^b1*p2^b2*p3^b3*...pn^bnp1,p2...pn为质数
a1~an,b1~bn为指数
最大公因数:gcd(A,B)=p1^min(a1,b1)*p2^min(a2,b2)*...*pn^min(an,bn)
最小公倍数:lcm(A,B)=p1^max(a1,b1)*p2^max(a2,b2)*...*pn^max(an,bn)
由此可得
假设a,b,c的公共质因子(底数)的指数分别为x,y,z
则(乘相当于指数相加,除相当于指数相减)
s可以看做x+y+z+max(x,y,z)-max(x,y)-max(x,z)-max(y,z)->答案应该是x,y,z中一个数
所以为使得s最大则只需要找到最大公约数
*/#include<bits/stdc++.h>
using namespace std;
const int N=1e5+6;
int a[N];
vector<int>fac[N];//存放每个数的因子。因为因子是不断放进来所以用动态数组vector,fac[i][j]表示i的第j个因子
vector<int>s[N];//s[i][j]表示i的第j个倍数,i为因子s[i]是找出以i为因子的所有数组成的数组
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){cin>>a[i];
}
//因为要输出字典序最小,所以先对a从小到大排序
sort(a+1,a+1+n);
//求每个数字的因子
for(int i=1;i<=1e5;i++){for(int j=i;j<=1e5;j+=i){//j为i的倍数
fac[j].push_back(i);//i是j的因子}
}
//求各因子对应的倍数(倍数是a数组里的数)
for(int i=1;i<=n;i++){//遍历a数组,求a数组里每个数的所有因子对应的a数组的数for(int j=0;j<fac[a[i]].size();j++){s[fac[a[i]][j]].push_back(a[i]);//表示a[i]的第j个因子对应的倍数有a[i]}
}//输出最大因子对应的三个倍数
for(int i=1e5;i>=1;i--)
{if(s[i].size()>=3){cout<<s[i][0]<<" "<<s[i][1]<<" "<<s[i][2];return 0;}
}return 0;
}

6.爬山

考点:优先队列(堆)

贪心思想:

每次对最大的那个数字操作-->大根堆(也就是优先队列的默认)

开根号比除以2减小的更快

代码:

//考点是优先队列(默认大根堆)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,p,q;
cin>>n>>p>>q;
priority_queue<int,vector<int> >d;//vector<int>后面需要有个空格
int h;
for(int i=0;i<n;i++){cin>>h;d.push(h);
}
for(int i=0;i<p;i++){int a=d.top();a=sqrt(a);d.pop();d.push(a);
}
for(int i=0;i<q;i++){int a=d.top();a/=2;d.pop();d.push(a);
}
long long int sum=0;
for(int i=0;i<n;i++){sum+=d.top();d.pop();
}
cout<<sum;
return 0;
}

堆总结 

c++里堆用priority_queue写

堆操作:

默认是大根堆,堆顶最大

大根堆写法:

priority_queue<int,vector<int> >

小根堆:

 priority_queue<int,vector<int>,greater<int> >q;

自定义堆:

用结构体struct自定义堆

例如:下面自定义的小根堆

//自定义堆 
#include<bits/stdc++.h>
using namespace std;
struct Com{bool operator()(int a,int b){return a>b;}
}; 
int main(){int n;cin>>n;priority_queue<int,vector<int>,Com >q;for(int i=0;i<n;i++){int a;cin>>a;q.push(a);}return 0;
}

 

说明这个结构体定义的是小根堆,数字越小优先级越高

8.拔河(非常难做)

暴力(四种循环,20%)

#include <iostream>
using namespace std;
long long int a[1003];
long long int ans;
long long int s(int l,int r){
long long int sum=0;for(int i=l;i<=r;i++){sum+=a[i];}return sum;
}
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];ans+=a[i];}for(int l1=1;l1<n;l1++){for(int r1=l1;r1<n;r1++){for(int l2=r1+1;l2<=n;l2++){for(int r2=l2;r2<=n;r2++){long long   int z=s(l1,r1);long long int y= s(l2,r2);ans=min(ans,abs(z-y));}}}}cout<<ans;return 0;
}

正解: 前缀和+multiset+lowerbound(100%)

完整的代码:

/*
分析:
考察:
1.区间和-->前缀和算法
2.最接近-->二分算法(可以用lowerbound解决),所以可以用multiset存储区间和,multiset自带lower_bound
multiset是可含重复元素的集合,并且默认升序排列,可以使用lowerbound,upper_bound
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N=1e3+6;
ll a[N];//原数列
ll s[N];//从头开始,前缀和
multiset<ll>m;//存区间和
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){cin>>a[i];
}
//前缀和
for(int i=1;i<=n;i++){s[i]=s[i-1]+a[i];
}
// //区间和(可以求得所有区间和)
// for(int i=1;i<=n;i++){
//   for(int j=1;j<=i;j++){
//     //计算区间[j,i]的和
//     ll h=s[i]-s[j-1];
//     m.insert(h);
//   }
// }
ll ans=1e9;//先放最大
//求解答案(做减法)
for(int l=1;l<=n;l++){
for(int j=1;j<l;j++){//第一个区间用multiset维护m.insert(s[l-1]-s[j-1]);
}
for(int r=l;r<=n;r++){//sum为区间[l,r]的和(第二个区间)ll sum=s[r]-s[l-1];//取出一个区间//利用lowerbound找与他最接近的区间和auto t=m.lower_bound(sum);//lowerbound返回第一个大于等于他的数的迭代器if(t!=m.end()){//表示存在大于等于他的数
ans=min(ans,abs(*t-sum));}if(t!=m.begin()){//比他小的t--;ans=min(ans,abs(*t-sum));}
}
}
cout<<ans;return 0;
}

 核心代码解释:

 (1)碰见区间求和要想到用前缀和的办法

前缀和模版

//前缀和(即区间[1,i]和)
for(int i=1;i<=n;i++){
  s[i]=s[i-1]+a[i];
}

(2)两个区间和计算,找最小差值

ll ans=1e9;//先放最大
//求解答案(做减法)
for(int l=1;l<=n;l++){
for(int j=1;j<l;j++){//第一个区间用multiset维护
  m.insert(s[l-1]-s[j-1]);
}
for(int r=l;r<=n;r++){
  //sum为区间[l,r]的和(第二个区间)
  ll sum=s[r]-s[l-1];//取出一个区间
  //利用lowerbound找与他最接近的区间和
  auto t=m.lower_bound(sum);//lowerbound返回第一个大于等于他的数的迭代器
  if(t!=m.end()){//表示存在大于等于他的数
ans=min(ans,abs(*t-sum));
  }
  if(t!=m.begin()){//比他小的
   
    t--;
    ans=min(ans,abs(*t-sum));
  }
}
}
cout<<ans;

lowerbound在这道题的作用:

先取出一个右边区间的和,然后在左边找一个最接近他的区间和,左边各区间和用multiset维护,找寻第一个大于等于他的数用lowerbound,返回迭代器。

然后也可能左边区间和比他小的那个作差绝对值更小,所以用迭代器向前一位的区间和算一下试试。

删除时如果用数字删会删全部,如果用迭代器删只删除指定位置

7.数字接龙

#include<bits/stdc++.h> 
using namespace std;
const int N=20;
int a[N][N];//存放图
string path;//存路径
bool st[N][N];//存这个点是否经过
bool edge[N][N][N][N];//edge[i][j][x][y]表示起点(i,j)终点(x,y)的斜线是否经过 处理交叉问题
int n,k;
//方向向量
int dx[]={-1,-1,0,1,1,1,0,-1};//0-7 行 
int dy[]={0,1,1,1,0,-1,-1,-1};//列 
bool dfs(int x,int y){if(x==n-1&&y==n-1){//搜到终点 return path.size()==n*n-1;//如果恰好经过n*n-1步到达终点,说明方案可行的 }st[x][y]=true;//经过当前点for(int i=0;i<8;i++) {int bx=x+dx[i];int by=y+dy[i];if(bx>=n||bx<0||by>=n||by<0){//越界continue; }if(st[bx][by]){continue;//经过了(防止重复走) }if(i%2&&(edge[bx][y][x][by]||edge[x][by][bx][y])){//只有斜线才防止交叉即1,3,5,7方向 continue; }if(a[bx][by]!=(a[x][y]+1)%k){//不满足走的要求continue;}edge[x][y][bx][by]=true;//恢复path+=i+'0';if(dfs(bx,by)){//注意只要找到了就可退出!!return true;}edge[x][y][bx][by]=false;path.pop_back();}st[x][y]=false;//恢复现场return false;//不存在路径
}
int main(){
cin>>n>>k;
for(int i=0;i<n;i++){for(int j=0;j<n;j++){cin>>a[i][j];}
}
if(!dfs(0,0)){//从起点(0,0) 开始搜没有搜到
cout<<"-1" ;
}
else{cout<<path;
}
return 0;
}

交叉:

双方向x,by->bx,y和bx,y->x,by如果存在 就交叉会和斜线方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/888226.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenWRT安装Caddy实现WebDAV协议的NAS盘

Caddy带有WebDAV插件,可以安装在OpenWRT上,用于提供WebDAV协议的NAS服务。 Windows资源管理器,WinSCP,MAC的Finder,Android上的CX文件管理器都可以作为WebDAV的客户端。 WebDAV使用过程中可以直接打开文件,修改后保存,非常方便,感觉Samb没区别。但其使用https协议,安全…

Java17的安装

Java17的安装因为要用SpringBoot3了,Java版本要更新到17以后 安装连接:Java Archive Downloads - Java SE 17.0.12 and earlier 下载 选择对应的版本下载安装可以更改安装位置成功以后关闭就行配置环境变量 如果电脑已经安装了JDK8,但又不想卸载的同时想安装JDK17,可以如下…

linux中nano和vim用法

Linux下nano,vim使用Linux 编辑器使用指南:nano 和 vim 在 Linux 系统中,编辑文本文件是非常常见的任务。对于大多数 Linux 用户来说,nano 和 vim 是两个最常用的命令行文本编辑器。虽然它们都可以用来编辑文件,但它们的功能和使用方式有很大不同。本篇文章将介绍这两个编辑…

final关键字、Object类

1.规则 被final修饰的变量,名称都要大写,多单词的名称则需_来分隔1.修饰方法method方法已经不能被重写了,因为修饰该方法的是final2.修饰类 当一个类中所有的成员方法都不想被重写时,可以直接在类上加上final,无需再一个一个写在方法上2.object类: 是所有类的祖宗,每一个…

Java要记-持续补充中

1. ArrayList操作自定义对象进行removeAll()时,移除失效原因 由于底层最用调用的是Object的equals()方法进行比较的,比较的是地址,两个对象地址当然是不同的了,移除自然会失败。解决方案:重写equals方法。【注意重写equals方法记得也要重写hashCode方法】同时:retainAll(…

this和super--java进阶day01

1.this和super的代表super是父类的标识符,如堆内存中的标志 2.this和super的访问重点说访问构造方法,super()访问父类构造方法我们已经清楚,但是this()访问本类构造方法,我们不清楚有什么用意义 如以下情境 假设在公司制作一个系统,1.0有三位角色随着版本更新,1.1要新…

软件开发与创新课程设计第一次作业---小游戏《勇者冒险》改写

《勇者冒险》小游戏代码优化 一、项目名称与来源 题目为《勇者冒险》(原项目没有名字,是作者取的),代码来源是CSDN,链接如下: https://blog.csdn.net/zjx120307/article/details/126221342?sharetype=blog&shareId=126221342&sharerefer=APP&sharefrom=qq 本…

多周期处理器debug记录

这篇随笔记录的是从普通的多周期处理器到加入握手信号和axi-lite协议sram的处理器。 在之前的多周期处理器里,由于结构比较简单,所以我给ifu和exu的握手信号加入的是时序逻辑,idu由于只做解码,所以握手信号放在了组合逻辑里,差不多就和透传差不多。但是加入sram握手信号以…

继承内存图--java进阶 day01

主方法进栈,有new进堆堆内存中先存自己类中有的变量又因为继承了父类,所以父类中的变量也要存入 即使被私有化,依旧可以继承,只是没有权限使用!创建对象时,会调用构造方法,所以走构造方法,实参传形参.....继续走到super,访问父类的构造方法,父类构造方法进栈,形参继…

离散化学习笔记

离散化学习笔记 OP:又是一如既往的周更。。。水死了 定义离散化:将数字映射为是第几小的数,其保证数据在Hash之后仍然保持原来的全/偏序关系,能够解决:通过元素相对大小即可解决的问题。 其实本质上就是哈希的一种特殊规则而已。(离散化简化了不止亿点)目标将一堆乱序且…

java知识面试day2

1.说出java和c++的区别java是一个纯粹的面向对象语言,所有的对象都继承于java. lang.Object,C++兼容C,不但支持面向对象也支持面向过程 java有着一次编译四处运行的跨平台特性。 java不具有指针,但具有垃圾回收。 java不支持多重继承,只能通过实现多个接口去达到相同目的2.…

继承中构造方法访问特点--java 进阶day01

1.子类不可以继承父类的构造方法构造方法的名称必须与类名一致,上图中类名是Zi,而构造方法名是Fu,肯定不行 2.子类在初始化之前,需要对父类初始化 子类在初始化的过程中,很有可能会调用到父类的数据,如果父类没有提前初始化,子类就无法调用这些数据3.通过在子类中访问父…