蓝桥杯大学B组省赛2020模拟赛(一)题解与总结
题目链接:https://www.jisuanke.com/contest/6516
A:题目:
我们称一个数是质数,而且数位中出现了 5 的数字是有趣的。
例如 5, 59, 457。求1到100000中有趣的数的个数。
题解:无脑分解和暴力枚举素数即可。
代码:
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int mod = ;
bool check(int x)
{
int flag = ;
for (int i = ; i <= sqrt(x); i++)
if (x % i == )
flag = ;
if (flag == )return false;
else return true;
}
bool check2(int x)
{
int t;
while (x != )
{
t = x % ;
x = x / ;
if (t == )return true;
}
return false;
}
int main(void)
{
int num = ;
for (int i = ; i <= ; i++)
{
if (check(i) == true)
if (check2(i) == true)
num++;
}
cout << num << endl;
return ;
}
答案:3282
B:题目:
蒜头君要爬楼梯。楼梯一共有10层台阶。
因为腿长的限制,每次最多能上4层台阶。但是第5,7层楼梯坏掉了不能踩。求上楼梯的方案数。
题解:通过上一层转移,没啥坑。
代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int mod = ;
int dp[];
int main(void)
{
dp[] = ;
dp[] = dp[] + ;
dp[] = dp[] + dp[] + ;
dp[] = dp[] + dp[] + dp[] + ;
dp[] = ;
dp[] = dp[] + dp[] + dp[] + dp[];
dp[] = ;
for (int i = ; i <= ; i++)
dp[i] = dp[i - ] + dp[i - ] + dp[i - ] + dp[i - ];
cout << dp[] << endl;
return ;
}
答案:72
C:题目:求问在以下图案的大三角形内部添加五条直线最多可以将大三角形分成多少个区域。
请在下图的基础上添加五条直线。
题解:
答案:47
D:题目:
有3030个篮子,每个篮子里有若干个苹果,篮子里的苹果数序列已经给出。
现在要把苹果分给小朋友们,每个小朋友要么从一个篮子里拿三个苹果,要么从相邻的三个篮子里各拿一个苹果。(苹果可以剩余)
比如对于序列3 1 3,可以分给两个小朋友变成0 1 0;也可以分给一个小朋友变成2 0 2,此时不能继续再分了。所以答案是2。
求问对于以下序列{7,2,12,5,9,9,8,10,7,10,5,4,5,8,4,4,10,11,3,8,7,8,3,2,1,6,3,9,7,1}最多分给几个小朋友?
题解:本题考虑贪心,贪心的策略是:从左到右取苹果,使浪费的苹果最少。篮子中大于等于3个苹果的直接取3个,取到小于3个为止。然后将此篮子当作1 1 1取法的左端点,继续取,直到无法操作。
这样确保每次都是局部最优,因而推出整体最优。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
//尽可能少剩下的苹果最少为贪心思路
int main()
{
ios::sync_with_stdio(false);
int sum = ;
int a[] = { ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, };
int ans = ;
for (int i = ; i <= ; ++i)
{
ans += a[i] / ;
a[i] %= ;
/*
for (int i = 1; i <= 30; i++)
cout << a[i] << " ";
cout << endl;
*/
while (a[i] >= && a[i + ] >= && a[i + ] >= )
{
a[i]--; a[i + ]--; a[i + ]--;
ans++;
}
}
cout << ans << endl;
return ;
}
答案:62
E:题目:
广场上的小朋友们排成了整齐的方阵。具体来说,我们可以把每个小朋友看做是一个点,那么小朋友们就形成了n×n的点阵。
方阵中,小朋友A和小朋友B互相可以看见,当且仅当二人之间的连线不经过别的小朋友,且他们之间的距离不超过k。我们想知道有多少对小朋友互相可以看见。(A,B)与 (B,A)算同一对。
例如,n=2,k=1时答案为4,n=2,k=2 时答案为6,n=3,k=2时答案为20。
现在我们想要知道,当n=1000,k=500时的答案是多少。由于答案过大,请回答对10^9+7取模后的结果。
分析:本题是填空题中唯一有难度的一问,坑点较多。(ps:用了对拍才找到自己的错误)
题解:
代码:(正确代码)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + ;
int main()
{
int n, k;
cin >> n >> k;
ll ans = * n * (n - ) % MOD;//边框上的线数目
for(int x = ; x <= n; x++)
{
for(int y = ; y <= n; y++)
{
if(x * x + y * y > k * k)continue;
if(__gcd(x, y) != )continue;
ans = (ans + * (n - x) * (n - y)) % MOD;
}
}
cout<<ans;
return ;
}
解释:对于代码中ans的解释
暴力对拍代码:(直接跑可能要3000s才能出答案)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + ;
int main()
{
int n, k, ans = ;
cin >> n >> k;
///第一个点(sx, sy) 第二个点(tx, ty)
for(int sx = ; sx <= n; sx++)
{
for(int sy = ; sy <= n; sy++)
{
for(int tx = ; tx <= n; tx++)
{
for(int ty = ; ty <= n; ty++)
{
if(sx == tx && sy == ty)continue;
if((tx - sx) * (tx - sx) + (ty - sy) * (ty - sy) > k * k)continue;
if(__gcd(abs(tx - sx), abs(ty - sy)) != )continue;
ans++;
}
}
}
}
cout<<ans / ;
return ;
}
答案:916585708
F:题目:
题解:直接用map或者set存即可,数据范围不大,不会mle或者tle。
坑点:要把a0=1提前存入,不然就会只有13/15分。(别问为啥知道,问就是白给)
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
const int mod = ;
ll A, B, C;
int a[];
map<int, int>m;
int main(void)
{
cin >> A >> B >> C;
int flag = ;
a[] = ;
m[] = ;
for (int i = ; i <= ; i++)
{
a[i] = (A * a[i - ] + a[i - ] % B) % C;
if (m[a[i]] == )
m[a[i]]++;
else
{
cout << i << endl;
return ;
}
}
cout << "-1" << endl;
return 0;
}
G:题目:
分析:一道稍微有点繁琐,题面有错的模拟。
输出的第一行,应该是被破坏的道路,房屋,田地的总数。(十分的蛋疼,比赛的时候完全按照题面只有2/20分)
注意:
①溅射伤害是高级炮弹击中的k*k区域的每一小块周围的8小块都会受到的伤害。
②该开long long的地方不要吝啬。
代码:(按照修改后的题意)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
using namespace std;
typedef long long ll;
const int mod = ;
const int maxn = ;
ll blood[];//三种血量
ll sum[];//三种受的伤
int mp[maxn][maxn];//编号地图
ll now[maxn][maxn];//血量地图
ll hurt[maxn][maxn];//基本伤害
int dx[] = { ,,,-,,,-,- };
int dy[] = { ,-,,,,-,,- };
int main(void)
{
ios::sync_with_stdio(false);
int n, m; cin >> n >> m;
cin >> blood[] >> blood[] >> blood[];
int k; ll w;//范围与溅射伤害
cin >> k >> w;
for (int i = ; i <= k; i++)
for (int j = ; j <= k; j++)
cin >> hurt[i][j];
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
cin >> mp[i][j];
now[i][j] = blood[mp[i][j]];
}
//计算攻击
int q; cin >> q;
while (q--)
{
int op, x, y;
cin >> op >> x >> y;//爆炸中心x y
int s1, s2, e1, e2;
s1 = max(, x - k / );//行开始
e1 = min(n, x + k / );//行结束
s2 = max(, y - k / );//列开始
e2 = min(m, y + k / );//列结束
for (int i = s1; i <= e1; i++)
{
for (int j = s2; j <= e2; j++)
{
int ii = (i - x) + (k + ) / ;//相对中心点的位置
int jj = (j - y) + (k + ) / ;
if (now[i][j] > )//在受到炸弹之前还有血
{
sum[mp[i][j]] += min(now[i][j], hurt[ii][jj]);
now[i][j] -= hurt[ii][jj];
if (now[i][j] < )
now[i][j] = ;
}
if (op == )//若有溅射伤害
{
for (int f = ; f < ; f++)
{
int i_new = i + dx[f];
int j_new = j + dy[f];
if (i_new< || i_new>n || j_new< || j_new>m) continue;
if (now[i_new][j_new] > )//在受到溅射之前还有血
{
sum[mp[i_new][j_new]] += min(now[i_new][j_new], w);
now[i_new][j_new] -= w;
if (now[i_new][j_new] < )
now[i_new][j_new] = ;
}
}
}
}
}
}
int ans[] = { };
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
ans[mp[i][j]] += (now[i][j] == );
cout << ans[] << " " << ans[] << " " << ans[] << endl;
cout << sum[] + sum[] + sum[] << endl;
return ;
}
H:题目:
分析:如果按位展开,每次都暴力计算判断是否乘除的话,必然拿不到满分(强数据会tle)。
所以在计算是否整除的时候做了以下优化:
①第一次计算总和时,借助了已经打好的按位取模后的乘权表
②之后双重for循环找交换的两位字母,在取模环境下,减去两个换前原字母所对应的值,加上两个换后字母对应的值进行O(1)的更新判断。
可行性分析:在无除法的运算过程中,加法和乘法的同余模定理确保了对每一步都取模后的结果不会让最后的答案不变。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll; ll f[];///f[i] = 26^i % M
int main(void)
{
string s;
cin >> s;
ll M;
cin >> M;
f[] = % M;
int n = s.size();
for (int i = ; i <= n; i++)
f[i] = f[i - ] * % M; ll sum = ;
for (int i = ; i < n; i++)
sum = (sum + f[n - - i] * (s[i] - 'A')) % M;
if (sum == )
{
cout << "0 0" << endl;
return ;
}
else
{
for (int i = ; i < s.size(); i++)
{
for (int j = i + ; j < s.size(); j++)
{
ll tmp = sum;
tmp = ((tmp - f[n - - i] * (s[i] - 'A')) % M + M) % M;
tmp = ((tmp - f[n - - j] * (s[j] - 'A')) % M + M) % M;
tmp = ((tmp + f[n - - i] * (s[j] - 'A')) % M + M) % M;
tmp = ((tmp + f[n - - j] * (s[i] - 'A')) % M + M) % M;
if (tmp == )
{
cout << i + << " " << j + << endl;
return ;
}
}
}
}
cout << "-1 -1" << endl;
return ;
}
注意:避免产生负数,取模之后的减法要加上模数,再取模确保计算结果为正。
I:题目:
分析:显然,这一题的数据不能一个点跑一次dijkstra。我们发现对于起点1到所有点的最短路,可以一次dijkstra完成。但如果此时,选择每一目的地出发,跑dijkstra,那需要再跑n-1次,显然不是明智的选择。
我们可以通过将边反存,这样所有从非起点指向1的边变成了1指向所有目的地。只要再dijkstra一次反向存边,便可计算出从目的地返回起点的最短路。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = ;
const ll INF = 1e15;
struct edge
{
int v, w;///v表示终点 w表示边长
edge() {}
edge(int vv, int ww){v = vv;w = ww;}
};
struct Heapnode
{
int id;
ll d;///id表示节点的编号,d表示从s走到id的距离
Heapnode() {}
Heapnode(int id, ll d) :id(id), d(d) {}
bool operator <(const Heapnode& a)const
{
return d > a.d;
}
};
vector<edge>Map[][maxn];
int n, m;
///添加一条从u出发到v结束,边长为w的边
void addedge(int u, int v, ll w)
{
Map[][u].push_back(edge(v, w));
Map[][v].push_back(edge(u, w));///反向建图
}
ll d[][maxn];///d[i]表示从s出发,到达i的最短距离
bool vis[maxn];
void Dijkstra(int s, int id)
{
for (int i = ; i <= n; i++)d[id][i] = INF, vis[i] = ;
d[id][s] = ;
priority_queue<Heapnode>q;
q.push(Heapnode(s, ));
while (!q.empty())
{
Heapnode now = q.top();
q.pop();
int u = now.id;
if (vis[u])continue;
vis[u] = ;
for (int i = ; i < Map[id][u].size(); i++)
{
///u -> v 边长为w
int v = Map[id][u][i].v;
int w = Map[id][u][i].w;
if (d[id][u] + w < d[id][v])
{
d[id][v] = d[id][u] + w;
q.push(Heapnode(v, d[id][v]));
}
}
}
}
int main(void)
{
ios::sync_with_stdio(false);
int T;
cin >> T;
while (T--)
{
cin >> n >> m;
for (int i = ; i <= n; i++)
Map[][i].clear(), Map[][i].clear();
ll sum = ;
for (int i = ; i <= m; i++)
{
int u, v; ll w;
cin >> u >> v >> w;
addedge(u, v, w);
}
Dijkstra(, );
Dijkstra(, );
for (int i = ; i <= n; i++)
sum += d[][i] + d[][i];
cout << sum << endl;
}
return ;
}
注意:不确定数值大小的话,都用long long(除了恶心的多校之外,一般不会卡ll);初始化的INF一定要大一些,如果使用0x3f3f3f3f会出错
J:题目:
分析:这是一题很棒的搜索题,题目中说确保每个点是至多是一个传送门的入口(仅仅只能说明传送门的出度是唯一的,即一个传送门对应一个目的地)
例如下图,
因此说明,传送门的传送位置是传送门;传送门死循环等状况也是可能的。
所以对于任意一点非障碍物a有以下情况:
(一)a是传送门
1:经过终点
2:传n次,落在合法位置
3:传n次,卡在障碍物
4:死循环
(二)a不是传送门
所以如果利用队列,我们需要将下一个即将压入队列的点进行预处理,才能当作正常bfs搜索操作。
难点处理:我们利用了map去映射传送门的起点对和终点对,写了函数Find_Next(a)去寻找点a进入传送门后的结果
1:正常情况:返回出口
2:卡在障碍物:返回-1,-1
3:死循环:返回-1,-1
4:只要经过终点:返回终点
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;const int N = ;
const int inf = 0x3f3f3f3f;
char Mp[N][N];//地图
bool vis[N][N];//标记
int dx[] = { ,-,, };
int dy[] = { ,,,- };
int x, y;//目的地
int n, m;
typedef pair<int, int> Pair;
map<Pair, Pair>door;
struct node
{
int x, y, num;
node() {}
node(int xx, int yy, int nnum) { x = xx; y = yy; num = nnum; }
node(Pair a, int nnum)
{
x = a.first;
y = a.second;
num = nnum;
}
};
///a是传送门入口 返回传送门出口
///1:正常情况:返回出口
///2:卡在障碍物:返回-1,-1
///3:死循环:返回-1,-1
///4:只要经过终点:返回终点
Pair Find_Next(Pair a)
{
Pair start = a;
set<Pair>s;///走过的点全都塞入s中
while (true)
{
if (a.first == x && a.second == y)return make_pair(x, y);
if (Mp[a.first][a.second] == '*')return make_pair(-, -);
if (door.count(a))
{
if (s.count(a))return make_pair(-, -);
s.insert(a);
a = door[a];
}
else return a;
}
} int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = ; i <= n; i++)
cin >> (Mp[i] + );
int k;
cin >> k;
while (k--)
{
int a, b, c, d;
cin >> a >> b >> c >> d;
door[make_pair(a, b)] = make_pair(c, d);
}
cin >> x >> y;
Pair Start = make_pair(, );
if (Find_Next(Start).first == -)
{
cout << "No solution" << endl;
return ;
}
queue<node>q;
Start = Find_Next(Start);
q.push(node(Start, ));
vis[Start.first][Start.second] = ;
while (!q.empty())
{
node now = q.front();
q.pop();
if (now.x == x && now.y == y)
{
cout << now.num << endl;
return ;
}
for (int i = ; i < ; i++)
{
int xx = now.x + dx[i];
int yy = now.y + dy[i];
if (xx < || xx > n || yy < || yy > m)continue;
if (Mp[xx][yy] == '*')continue;
if (vis[xx][yy])continue;
Pair Next = Find_Next(make_pair(xx, yy));
//cout<<xx<<" "<<yy<<" "<<Next.first<<" "<<Next.second<<endl;
if (Next.first == -)continue;
q.push(node(Next, now.num + ));
vis[Next.first][Next.second] = ;
}
}
cout << "No solution" << endl;
return ;
}
Ps:题目数据似乎不强,没有涉及到传送门死循环的数据,但是处于严谨还是考虑上啦(毕竟补题)
蓝桥杯大学B组省赛2020模拟赛(一)题解与总结的更多相关文章
- (acwing蓝桥杯c++AB组)1.1 递归
(acwing蓝桥杯c++AB组)1.课程介绍+递归 文章目录 (acwing蓝桥杯c++AB组)1.课程介绍+递归 课程介绍 第一讲 递归与递推 递归 引入 递归的底层调用顺序 例题与练习 课程介绍 ...
- Java实现 第十一届 蓝桥杯 (本科组)省内模拟赛
有错误的或者有问题的欢迎评论 计算机存储中有多少字节 合法括号序列 无向连通图最少包含多少条边 字母重新排列 凯撒密码加密 反倍数 正整数的摆动序列 螺旋矩阵 小明植树 户户通电 计算机存储中有多少字 ...
- 2019第十届蓝桥杯C++B组题解(赛后重写的,不确保答案正确性,仅供参考)
先说一下这次的感受吧,我们考场比较乱,开始比赛了,还有的电脑有故障,(向这些人发出同情),第一次认真参加比赛,真正比赛的时候感觉没有那么正式,很乱,各种小问题,(例如博主就没找到题目在哪里,找到后又不 ...
- 第八届蓝桥杯java b组第六题
标题:最大公共子串 最大公共子串长度问题就是:求两个串的所有子串中能够匹配上的最大长度是多少. 比如:"abcdkkk" 和 "baabcdadabc",可以找 ...
- [18/12/3]蓝桥杯 练习系统 入门级别 Fibonacci数列求模问题 题解思路
前言略. 看到这个题目本来应该很高兴的,因为什么,因为太TM的基础了啊! 可是当你用常规方法尝试提交OJ时你会发现..hhh...运行超时..(开心地摇起了呆毛 //Fibonacci数列递归一般问题 ...
- 第六届蓝桥杯C++B组省赛
1.奖券数目 2.星系炸弹 3.三羊献瑞 4.格子中输出 5.九数组分数 6.加法变乘法 7.牌型种数 8.移动距离 9.垒骰子 10.生命之树 1.奖券数目 奖券数目有些人很迷信数字,比如带“4”的 ...
- 第三届蓝桥杯C++B组国(决)赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.星期几 1949年的国庆节(10月1日)是星期六. 今年(2012)的国庆节是星期一. 那么,从建国到现在,有几次国庆节正好是星期日呢 ...
- 第七届蓝桥杯C++B组省赛
1.煤球数目 2.生日蜡烛 3.凑算式 4.快速排序 5.抽签 6.方格填数 7.剪邮票 8.四平方和 9.交换瓶子 10.最大比例 今天是周三了,周天刚考完,这次做的还是不好(上次是全省最后一名). ...
- 2012年第三届蓝桥杯Java本科组省赛试题解析
题目地址:https://wenku.baidu.com/view/326f7b4be518964bcf847c96.html?rec_flag=default => 百度文档 题目及解析 ...
随机推荐
- sort运用
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; struc ...
- 制作sentinel docker镜像
在sentinel官方下载jar包即可运行,但是在部署的时候一个一个的启动jar包很不方便,制作成镜像方便部署和管理. 1)直接运行 # 修改端口号,默认是8080 java -jar sentine ...
- Nlog打印日志到Influxdb数据库
1.安装和使用Influxdb 安装部分网上资料比较多,也讲的比较详细,请自行百度. 下面大概讲下InfluxDB的写入和读取数据的方法. 我使用了InfluxData.Net包. 工具->Nu ...
- 关联函数-web_reg_save_param
int web_reg_save_param(const char *ParamName,<List of Attributes>,LAST) 返回值:成功时返回LR_PASS,失败时返回 ...
- 基于JQuery的简单富文本编辑器
利用jQuery实现最简单的编辑器 我试了很多种方法,目前最快捷能够实现及其简单的编辑可以使用 document.execCommand("ForeColor", "fa ...
- 附016.Kubernetes_v1.17.4高可用部署
一 kubeadm介绍 1.1 概述 参考<附003.Kubeadm部署Kubernetes>. 1.2 kubeadm功能 参考<附003.Kubeadm部署Kubernetes& ...
- ComplexHeatmap|根据excel表绘制突变景观图(oncoplot)
本文首发于“生信补给站”:https://mp.weixin.qq.com/s/8kz2oKvUQrCR2_HWYXQT4g 如果有maf格式的文件,可以直接oncoplot包绘制瀑布图,有多种展示和 ...
- MFC编辑框接收数据动态更新与刷新方法代码示例-如何让编辑框内容实时更新
MFC编辑框接收数据动态更新与刷新方法代码示例-如何让编辑框内容实时更新 关键代码: //发送数据通知 //from txwtech@163.com LRESULT CCommSampleDlg::O ...
- Linux下安装java环境
准备工作: linux环境 xshell6 1.在Windows本地www,oracle.com下载对应的linux系统的JDK安装包,我下载的是 2.下载下来后,通过xftp远程传输到linux服务 ...
- Java并发编程:Callable、Future和FutureTask 实现龟兔赛跑
1.不清楚的看博客http://www.cnblogs.com/dolphin0520/p/3949310.html 我们使用上面的代码来实现一个龟兔赛跑 package com.weiyuan.te ...