2018蓝桥杯省赛B组
2018蓝桥杯省赛B组
6.第几天
计算的代码
#include<bits/stdc++.h>
using namespace std;
int ans;
int main()
{
int m[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//考:每个月天数的表示
int y1=1;
int r1=1;
int y2=5;
int r2=4;
while(!((y1==y2)&&(r1==r2))){
r1++;
if(r1>m[y1]){
r1=1;
y1++;
}
ans++;
}
cout<<ans+1;
// 请在此输入您的代码
return 0;
}
A.明码
//第一步弄清楚这段文字是什么这是个汉字
#include<bits/stdc++.h>
using namespace std;
void two(int i,string&a){
//对于一个整数化成8位二进制,范围-128~127,对于正数最高位在二进制中是0也就是默认的-,对于负数最高位是1
if(i>=0){
for(int j=0;j<7;j++){
if((i>>j)&1==1){
a[8-j-1]='1';
}
}
}
else{//负数
a[0]='1';
for(int j=0;j<7;j++){
if(((128+i)>>j)&1==1){
a[8-j-1]='1';
}
}
}
}
int main(){
/*解析:题目中说有十个汉字,刚好十行,一行一个汉字!然后 一个汉字十六行,一行2个字节,所以一个汉字32个字节,刚好一行32个整数,所以一个整数
表示1个字节,所以我们的任务是将每个汉字的字形先输出按照一行两字节(2个整数-->化成2进制)一个汉字16行,然后通过汉字读懂题最后输出答案。
关键:将任意整数化成二进制
怎么看:1为墨迹要看的,-不管
*/
for(int i=0;i<10;i++){//10个整数
for(int j=0;j<16;j++){//1个整数16行,1行两字节(2个是十进制整数)
int x,y;
cin>>x>>y;
//先默认一行的两字节,等会儿只用看哪一位化成二进制是1,如果是0就不用变还是-
string a="--------";
string b="--------";
two(x,a);
two(y,b);
cout<<a+b<<endl;
}
cout<<"====================================================";//下一个汉字
}
return 0;
}
//第二步计算要提交的答案-->上面文字为9的9次方等于多少?
#include<bits/stdc++.h>
using namespace std;
int main(){
long long int ans=1;
for(int i=0;i<9;i++){
ans*=9;
}
cout<<ans;
return 0;
}
//填空题只用提交答案
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"387420489 ";
return 0;
}
考点:
读懂题-->确定是考察化整数为二进制
化成二进制模版
void two(int i,string&a){
//对于一个整数化成8位二进制,范围-128~127,对于正数最高位在二进制中是0也就是默认的-,对于负数最高位是1
if(i>=0){
for(int j=0;j<7;j++){
if((i>>j)&1==1){
a[8-j-1]='1';
}
}
}
else{//负数i和正数128+i只有最高位不同
a[0]='1';
for(int j=0;j<7;j++){
if(((128+i)>>j)&1==1){
a[8-j-1]='1';
}
}
}
}
B.乘积尾零
考点:
有点类似于试除法求约数
对于末尾为0可以考虑成2*5=10所以只需要计算所有输入的数可以分解成几个2几个5先分解2分解5都行,然后取因数为2,5个数最少的那个。
递增三元组
考点:
1.stl二分
lower_bound( )//大于等于
upper_bound( )//大于
用法:
利用二分查找stl必须保证数组有序
1.查找第一个大于等于这个数
(1)得第一个大于等于这个数的数字下标
lower_bound(数组名+查找起点,数组名+查找终点+1,查找数)-数组名
(2)返回指向大于等于这个数的第一个数字的指针
lower_bound(数组名+查找起点,数组名+查找终点+1,查找数)
(3)返回指向大于等于这个数的第一个数字的指针
*lower_bound(数组名+查找起点,数组名+查找终点+1,查找数)
2.查找第一个大于这个数
(1)得第一个大于这个数的数字下标
upper_bound(数组名+查找起点,数组名+查找终点+1,查找数)-数组名
(2)返回指向大于这个数的第一个数字的指针
upper_bound(数组名+查找起点,数组名+查找终点+1,查找数)
(3)返回指向大于这个数的第一个数字的指针
*upper_bound(数组名+查找起点,数组名+查找终点+1,查找数)
例如:
#include<bits/stdc++.h>
using namespace std;
int main(){
int a[5]={1,3,5,9,19};
cout<<*upper_bound(a,a+5,5);
return 0;
}
2.关键:
要将中间b数组作为参照,a数组中取比他小的有x个,c数组中取比他大有y个,那对于当前b中这个元素满足条件三元组有x*y个。
要乘法和stl否则超时
完整代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+6;
int a[N];
int b[N];
int c[N];
int main(){
int n;
cin>>n;
//1.输入a,b,c数组
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>b[i];
}
for(int i=0;i<n;i++){
cin>>c[i];
}
//2.排序
sort(a,a+n);
sort(b,b+n);
sort(c,c+n);
long long int ans=0;//答案怕太大所以long long
//3.以b做参考
for(int i=0;i<n;i++){
//(1)第一个比b[i]大于等于的a中数的下标(我们不要的)也是比b[i]小的a里面数的个数
int x=lower_bound(a,a+n,b[i])-a;
//(2)第一个比b[i]大于的c中数的下标(我们要的)
int y=n-(upper_bound(c,c+n,b[i])-c);
ans+=x*y;
}
cout<<ans;
return 0;
}
1.乘积最大
考双指针+分类讨论(可以尝试取数个数的奇偶来看)
日志统计:
暴力+stl
思路:先用个容器存放每个id对应的多个时间点接收到,然后检验每个id是不是热帖
检验每个id是不是热帖:
首先对该id的发送时间数组进行从小到大排序,然后枚举有可能的该id满足条件的第一个发送时间,然后对从该发送时间往后数看有没有可能满足热帖条件,只要有一种开头满足就可以跳出这个循环并输出该id判断条件是个数满足k个在d时间范围内!
快速排序
#include<bits/stdc++.h>
using namespace std;
与我们所学快排是反着的参照数据放最右侧这道题目。
int quick_select(int a[], int l, int r, int k) {
int p = rand() % (r - l + 1) + l;//生成一个[l,r]的下标
int x = a[p];//随机生成值
{int t = a[p]; a[p] = a[r]; a[r] = t;}//a[p]放最右边,参照值在右边
int i = l, j = r;
while(i < j) {
while(i < j && a[i] < x) i++;
if(i < j) {
a[j] = a[i];
j--;
}
while(i < j && a[j] > x) j--;
if(i < j) {
a[i] = a[j];
i++;
}
}
a[i] = x;
p = i;
if(i - l + 1 == k) return a[i];//答案
理由是右半边一定不是第k小的应该减去前面比他小的。
这个题考快速排序,将数列分成两部分,一部分比参照数据(随机数)小,一部分比他大。
if(i - l + 1 < k) return quick_select( a,i,r,k-(i-l) ); //填空
else return quick_select(a, l, i - 1, k);
}
int main()
{
int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
printf("%d\n", quick_select(a, 0, 14, 5));
return 0;
}
全球变暖
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n;
char g[N][N];//存放地图
bool st[N][N];//这个点是否被访问
#define x first
#define y second
typedef pair<int,int >PII;
PII q[N*N];//n*n个点,所以用n*n个组合
int ddx[4]={-1,0,0,1 };//x坐标变化(行)
int ddy[4]={0,-1,1,0};//y坐标变化(列)
void bfs(int sx,int sy,int &total,int &bound){
q[0]={sx,sy};
st[sx][sy]=true;//访问这个点
int hh=0;//队头
int tt=0;//队尾
while(hh<=tt){
PII t=q[hh++];//取队头
total++;
bool is_bound =false;
//以队头为中心四个方向
for(int i=0;i<4;i++){
int dx=t.x+ddx[i];
int dy=t.y+ddy[i];
//1.不重复访问
if(st[dx][dy])continue;
if(dx<0||dx>=n||dy<0||dy>=n)continue;//出界
//如果是海
if(g[dx][dy]=='.'){
is_bound=true;
continue;
}
//不是海,就加入到连通块里
q[++tt]={dx,dy};
st[dx][dy]=true;//加入连通块同时被搜到了
}
if(is_bound)bound++;
}
}
int main(){
cin>>n;
//存地图
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>g[i][j];
}
}
//开始搜,计算被淹没岛屿数
int cnt=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(!st[i][j]&&g[i][j]=='#'){
int total=0;
int bound =0;
bfs(i,j,total,bound);
if(total==bound)cnt++;
}
}
}
cout<<cnt;//被淹没的岛屿数
}

题目分析:
计算被淹没的岛屿数
首先确定考点搜索,将每个点搜一遍,但其实是对没有搜过的陆地进行宽搜看他所在岛屿(连通块)是否被淹没
是否被淹没看两个指标
即如果组成连通块的陆地数等于沿海边界数那么就是被淹没了统计上。
所以我们bfs(起点行坐标,起点列坐标,组成连通块的陆地数,沿海边界的陆地数)
这个bfs无返回值
对于这个bfs的写法
对于bfs他是依赖队列的,手写队列肯定要定义队头队尾,初始队头队尾均为0(下标)。因为要存放横纵坐标所以用pair型,define可以对first,second进行简写。
先将传入点放进队列,并访问st[][ ]=true;
然后就是while(hh<=tt){//队头下标小于等于队尾
取队头
组成该连通块的陆地数+1
队头是否是边界先默认false
对队头上下左右四个方向进行访问,
四种情况
出界 continue
访问过 continue
是海 那么这个队头沿海bool就要设置为true ,continue
最后是他也是陆地那么加进这个连通块里(入队),并且因为判断该他是陆地也就是搜索过了所以st[ ][ ]设置为true
如果沿海bool是true那么他就是边界bound++
}
测试次数
螺旋折线
直接模拟会超时(50%)
所以要找规律
对于这种正方形的问题关键是四条边
分类讨论在每条边要满足的条件和当前这种情况的距离公式
关键就是正方形的四个顶点的距离表达公式要求出来,然后在哪条边再用它改造。、
按位置分分四类:
在上面 |x|<=y
在右边 |y|<=x
在下边 |x|<=|y|+1 &&y<=0 (为防止y>0)
在左边 |y|<=|x|
n指的是从内向外数的层数如(3,3)在第三层
四个角离原点距离公式
左上角 2*n*(2*n-1)
右上角 (2*n)*(2*n)
右下角 (2*n+1)*(2*n)
左下角 (2*n-1)*(2*n-1)
在四种不同边上点的距离公式
上 :
参照左上角的点
dis(x,y)=2*n*(2*n-1)+x-(-n)
下:
参考右下角的点
(2*n+1)*(2*n)+n-x
左:
参考左下角的点
(2*n-1)*(2*n-1)+y-(-(n-1))
右:
参考右上角的点
2*n*(2*n)+n-y
计算层数:
层数:由内向外数圈数如下图:
完整代码
#include<bits/stdc++.h>
using namespace std;
//因为最外圈一条边就10的9次方,所以会爆int
typedef long long int ll;
int main(){
int x,y;
ll n;//n为层数
cin>>x>>y;//求dis(x,y)
ll dis=0;
if(abs(x)<=y){//上面
n=y;
dis=(ll)2*n*(2*n-1)+x-(-n);
}
else if(abs(y)<=x){//右边
n=x;
dis=(ll)2*n*(2*n)+n-y;
}
else if(abs(x)<=abs(y)+1&&y<=0){
//下边
n=abs(y);
dis=(ll)(2*n+1)*(2*n)+n-x;
}
else if(abs(y)<=abs(x)){//左边
n=abs(x);
dis=(ll)(2*n-1)*(2*n-1)+y-(-(n-1));
}
cout<<dis;
return 0;
}
注意事项:
else if摆的顺序有要求,因为他是不满足上面那个才进行下面那个,如果满足了那么下面都不进行
观察右边和左边如果左边这个算式不满足那右边式子更不满足那不满足左边那右边就不会判断了,所以对于有右边的判断要放在左边的前面。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人