目录
♥【分数】循环累乘/快速幂运算/最大公因数
♥【星期一】闰年/周期循环
♥【乘积尾零】遍历/取余/取整
♥【第几个幸运数】 遍历
♥【打印图形】dfs填空
×【航班时间】字符串/思维/时间换算
×【三体攻击】差分!中等难度
♥【全球变暖】dfs/连通块+计数
*【倍数问题】暴力/数论/构造
×【付账问题】贪心
【分数】循环累乘/快速幂运算/最大公因数
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
1+1/2+1/4+1/8+⋯
每项是前一项的一半,如果一共有 2020 项,求这个和是多少,结果用分数表示出来。
类似:3/2,当然,这只是加了前 2项而已。分子分母要求互质。
考点:循环累乘/快速幂运算
int gcd=__gcd(a,sum); //求最大公因数
#include<bits/stdc++.h>
using namespace std;
int main(){
int a=1;
int sum=0;
for(int i=1; i<=2020; i++){
sum=sum+a; //分子
a=a*2; //更新a,最终为分母
}
int gcd=__gcd(a,sum); //求最大公因数
a = a/gcd; //除法
sum = sum/gcd;
printf("%d/%d",sum,a/2);
}
【星期一】闰年/周期循环
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
整个 2020 世纪(1901 年 1 月 1 日至 2000年12 月 31 日之间),一共有多少个星期一?)5217
考点:闰年/周期循环
#include<bits/stdc++.h>
using namespace std;
//判断闰年
bool isleap(int x){
return x%400==0||(x%4==0&&x%100!=0);
}
int main(){
int t=0;
//计算总天数
for(int i=1901; i<=2000; i++){
if(isleap(i))
t+=366;
else t+=365;
}
//查日历已知2000年12月31日
//扣除26日至31日的6天
t-=6;
int res=0;
//从周一开始计数
for(int i=t; i>0; i-=7){
res++;
}
cout<<res<<endl;
}
【乘积尾零】遍历/取余/取整
乘积尾零 - 蓝桥云课 (lanqiao.cn)
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
如下的 1010 行数据,每行有 10个整数,请你求出它们的乘积的末尾有多少个零?
5650 4542 3554 473 946 4114 3871 9073 90 4329
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899
1486 5722 3135 1170 4014 5510 5120 729 2880 9019
2049 698 4582 4346 4427 646 9742 7340 1230 7683
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649
6701 6645 1671 5978 2704 9926 295 3125 3878 6785
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074
689 5510 8243 6114 337 4096 8199 7313 3685 211
方法1:遍历/取余/取整
方法2:先找出多少个能相乘等于零;计算出里面有多少个数是包含5和2;然后比较找出有多少个可以5和2可以相乘等于零;然后输出
#include<bits/stdc++.h>
using namespace std;
long long a[10][10];
int main(){
//读取数据
for(int i=1;i<=10;i++){
for(int j=1; j<=10; j++){
cin>>a[i][j];
}
}
//计算乘积
int count=0;
long long res=1;
long long x=1000000000;
for(int i=1;i<=10;i++){
for(int j=1; j<=10; j++){
//cout<<a[i][j]<<endl;
res=res*a[i][j];
//末尾为0计数
while(res%10==0){
res/=10;
count++;
}
res=res%x;
}
}
cout<<count<<endl;
}
#include <iostream>
using namespace std;
int cnt2,cnt5;
int a[100];
int main(){
for(int i=0;i<=99;i++){
cin>>a[i];
while(a[i]%2==0){
cnt2++;
a[i]/=2;
}
while(a[i]%5==0){
cnt5++;
a[i]/=5;
}
}
cout << min(cnt2,cnt5) << endl;
return 0;
}
【第几个幸运数】 遍历
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
到 X 星球旅行的游客都被发给一个整数,作为游客编号。
X 星的国王有个怪癖,他只喜欢数字 3,5 和7。
国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。
我们来看前 10 个幸运数字是:3,5,7,9,15,21,25,27,35,45因而第 11 个幸运数字是: 49
小明领到了一个幸运数字 59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。
请你帮小明计算一下,59084709587505是第几个幸运数字。 1905
方案:遍历
#include<bits/stdc++.h>
using namespace std;
int main(){
//目标 n = a*b*c
//a,b,c为3,5,7的倍数
long long n = 59084709587505;
int ans=0;
for(long long i=1; i<=n; i*=3){
for(long long j=1; i*j<=n; j*=5){
for(long long k=1; k*i*j<=n; k*=7){
ans++;
}
}
}
//排除1*1*1情况
cout << ans - 1;
return 0;
}
【打印图形】dfs填空
本题为代码补全填空题,请将题目中给出的源代码补全,并复制到右侧代码框中,选择对应的编译语言(C/Java)后进行提交。若题目中给出的源代码语言不唯一,则只需选择其一进行补全提交即可。复制后需将源代码中填空部分的下划线删掉,填上你的答案。提交后若未能通过,除考虑填空部分出错外,还需注意是否因在复制后有改动非填空部分产生错误。
如下的程序会在控制台绘制分形图(就是整体与局部自相似的图形)。
当 n=1,2,3 的时候,输出如下: 请仔细分析程序,并填写划线部分缺少的代码。
n=1 时:
o
ooo
o
n=2 时:
o
ooo
o
o o o
ooooooooo
o o o
o
ooo
o
n=3 时 :
o
ooo
o
o o o
ooooooooo
o o o
o
ooo
o
o o o
ooo ooo ooo
o o o
o o o o o o o o o
ooooooooooooooooooooooooooo
o o o o o o o o o
o o o
ooo ooo ooo
o o o
o
ooo
o
o o o
ooooooooo
o o o
o
ooo
o
方法: 图像类似向外扩张,优先随机设数,查看基础实现效果,dfs填空
#include <stdio.h>
#include <stdlib.h>
void show(char* buf, int w){
int i,j;
for(i=0; i<w; i++){
for(j=0; j<w; j++){
printf("%c", buf[i*w+j]==0? ' ' : 'o');
}
printf("\n");
}
}
void draw(char* buf, int w, int x, int y, int size){
if(size==1){
buf[y*w+x] = 1;
return;
}
//int n = _________________________ ; //填空
//int n = 1 ; //尝试效果 n=1 成立
int n = size/3 ;
draw(buf, w, x, y, n);
draw(buf, w, x-n, y ,n);
draw(buf, w, x+n, y ,n);
draw(buf, w, x, y-n ,n);
draw(buf, w, x, y+n ,n);
}
int main()
{
int N ;
scanf("%d",&N);
int t = 1;
int i;
for(i=0; i<N; i++) t *= 3;
char* buf = (char*)malloc(t*t);
for(i=0; i<t*t; i++) buf[i] = 0;
draw(buf, t, t/2, t/2, t);
show(buf, t);
free(buf);
return 0;
}
【航班时间】字符串/思维/时间换算
航班时间 - 蓝桥云课 (lanqiao.cn)
小 h 前往美国参加了蓝桥杯国际赛。小 h 的女朋友发现小 h 上午十点出发,上午十二点到达美国,于是感叹到"现在飞机飞得真快,两小时就能到美国了"。
小 h 对超音速飞行感到十分恐惧。仔细观察后发现飞机的起降时间都是当地时间。由于北京和美国东部有 12 小时时差,故飞机总共需要 14 小时的飞行时间。
不久后小 h 的女朋友去中东交换。小 h 并不知道中东与北京的时差。但是小 h 得到了女朋友来回航班的起降时间。小 h 想知道女朋友的航班飞行时间是多少。
对于一个可能跨时区的航班,给定来回程的起降时间。假设飞机来回飞行时间相同,求飞机的飞行时间。
方法:数学思维/思维/时间换算
#include<bits/stdc++.h>
using namespace std;
const int day = 24*60*60; //全部转化为秒
const int hour = 60*60;
const int minutes = 60;
int start() { //出发时间
int a,b,c;
scanf("%d:%d:%d",&a,&b,&c);
int time = a*hour + b*minutes + c;
return time;
}
int end() { //到达时间
int a,b,c;
scanf("%d:%d:%d",&a,&b,&c);
int time = a*hour + b*minutes + c;
char ch,extra_day;
while( (ch = getchar())!='\n' && ch != '\r' ) {
if(ch == '(') {
getchar(); //除去"+"
extra_day = getchar(); //额外天数
time = time + (extra_day - '0')*day;
}
}
return time;
}
void display(int time) { //显示时间
int a,b,c;
a = time/hour;
time = time % hour;
b = time / minutes;
time = time % minutes;
c = time;
printf("%02d:%02d:%02d\n",a,b,c);
}
int main() {
int h1,m1,s1,h2,m2,s2;
int t;
scanf("%d",&t);
while(t--) {
int start1 = start();
int end1 = end();
int start2 = start();
int end2 = end();
int ans = 0;
ans = (end1 - start1) + (end2 - start2); //相加
display(ans/2); //除2
}
return 0;
}
【三体攻击】差分!中等难度
三体攻击 - 蓝桥云课 (lanqiao.cn)
有难度的,暂不深入!
#include<iostream>
using namespace std;
const int N = 1000005;
int A, B, C, n, m;
int D[N];//三维差分数组 压维
int s[N];//存储舰队生命值
int x_1[N], y_1[N], z_1[N];//存储三体人的打击范围
int x_2[N], y_2[N], z_2[N];//存储三体人的打击范围
int d[N];//存储伤害
//将三维坐标转换为一维
int num(int x, int y, int z) {
if (x > A || y > B || z > C)return 0;
return ((x - 1) * B + (y - 1)) * C + (z - 1) + 1;
}
bool check(int x) {
for (int i = 1;i <= n;i++)D[i] = 0;
for (int i = 1;i <= x;i++) {
D[num(x_1[i], y_1[i], z_1[i])]+=d[i];
D[num(x_2[i] + 1, y_1[i], z_1[i])]-= d[i];
D[num(x_1[i], y_2[i] + 1, z_1[i])]-= d[i];
D[num(x_1[i], y_1[i], z_2[i] + 1)]-= d[i];
D[num(x_2[i] + 1, y_2[i] + 1, z_1[i])]+= d[i];
D[num(x_2[i] + 1, y_1[i], z_2[i] + 1)]+= d[i];
D[num(x_1[i], y_2[i] + 1, z_2[i] + 1)]+= d[i];
D[num(x_2[i] + 1, y_2[i] + 1, z_2[i] + 1)]-= d[i];
}
//将x,y看为定轴 对z进行累加
for (int i = 1;i <= A;i++) {
for (int j = 1;j <= B;j++) {
for (int k = 1;k <= C;k++) {
D[num(i, j, k + 1)] += D[num(i, j, k)];
}
}
}
//将x,z看为定轴 对y进行累加
for (int k = 1;k <= C;k++) {
for (int i = 1;i <= A;i++) {
for (int j = 1;j <= B;j++) {
D[num(i, j + 1, k)] += D[num(i, j, k)];
}
}
}
//将y,z看为定轴 对x进行累加
for (int j = 1;j <= B;j++) {
for (int k = 1;k <= C;k++) {
for (int i = 1;i <= A;i++) {
D[num(i + 1, j, k)] += D[num(i, j, k)];
}
}
}
for (int i = 1;i <= n;i++) {
if (D[i] > s[i])return true;
}
return false;
}
int main() {
cin >> A >> B >> C >> m;
n = A * B * C;
for (int i = 1;i <= n;i++) cin >> s[i];
for (int i = 1;i <= m;i++) {
cin >> x_1[i] >> x_2[i] >> y_1[i] >> y_2[i] >> z_1[i] >> z_2[i] >> d[i];
}
int L = 1;
int R = m;
while (L < R) {
int mid = (L + R) >> 1;
if (check(mid))R = mid;
else L = mid + 1;
}
cout << L << endl;
return 0;
}
【全球变暖】dfs/连通块+计数
dfs:深度优先遍历,问题1:递归深度深,栈内存不足!
bfs:宽度优先遍历,对象队列-官方
#include<bits/stdc++.h>
using namespace std;
int N;
const int SIZE = 1e4+4;
char area[SIZE][SIZE];
bool flag;
int cnt;
int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
//注意:求的是被淹没的岛屿的数量 总岛屿数量-被淹没的岛屿的数量
int ans=0; //没有被淹没岛屿的数量
int res_ans=0; //岛屿的总数量
//用DFS判断搜到的这个岛屿会不会被淹没,仅此而已,不需要返回什么 昨判断关系
void dfs(int x,int y)
{
//一个岛屿只要有一个点满足就不会变淹没了
if(flag==false){
cnt = 0;
for(int i=0; i<4; i++){
int tx=d[i][0]+x;
int ty=d[i][1]+y;
//四面环海
if(area[tx][ty]!='.')
cnt++;
}
//有一个点满足不会被淹没的条件
if(cnt==4){
ans++;
flag=true;//这个岛屿不需要再遍历了
}
}
area[x][y]='*';//将遍历过的点变为 *,下一次就不会遍历他了,所以不用标记数组
//注意这里不可以是‘.’因为上面if(area[tx][ty]!='.')cnt++
for(int i=0;i<4;i++){
int xx = x + d[i][0];
int yy = y + d[i][1];
//当前岛屿连接其他岛屿
if(area[xx][yy]=='#'&&x<N&&x>=0&&y<N&&y>=0)
dfs(xx,yy);
}
}
int main()
{
cin>>N;
//输入海洋和陆地的情况
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
cin>>area[i][j];
//遍历查找陆地的位置情况
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(area[i][j]=='#'){
res_ans++;
flag=false;
//判断当前岛屿会不会淹没
dfs(i,j);
}
}
}
cout<<res_ans-ans;
return 0;
}
【倍数问题】暴力/数论/构造
倍数问题 - 蓝桥云课 (lanqiao.cn)
蓝桥杯第 8-10 届真题解析 - 2018 年省赛真题 9 倍数问题-(思路 + C) - 蓝桥云课 (lanqiao.cn)
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。
根据规模拿分,暴力就暴力吧
自行加强,考前再看把。。。。。。
//基础分??
#include<bits/stdc++.h>
using namespace std;
int main(){
//n个正整数,选数要求是K的倍数
int n,k;
cin>>n>>k;
int a[n];
for(int i=0; i<n; i++){
cin>>a[i];
}
//符合条件的三个数和sum,最大的记为max
int sum=0;
int maxsum=0;
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
for(int z=j+1; z<n; z++){
sum = a[i]+a[j]+a[z];
if(sum%3==0) maxsum=max(sum,maxsum);
}
}
}
cout<<maxsum<<endl;
return 0;
}
【付账问题】贪心
蓝桥杯第 8-10 届真题解析 - 2018 年省赛真题 10 付账问题 - 蓝桥云课 (lanqiao.cn)
考前复习
贪心法:
- 准备贪心:先将花费数组从小到大排序
- 贪心策略:
- 从数组最小的元素开始,每次做判断
- 若当前元素小于剩余花费平均值,则取该元素不改变值,将平均成本转嫁到后续元素上
- 若当前元素大于等于剩余花费平均值,则后续元素也大于该平均值,能够承接前较小元素的成 本,将当前元素之后的所有元素取剩余花费平均值
- 结束贪心,解出标准差
精确度:
本题对于精确度要求较高,总结如下提升准确度的方法
- long long提升整数的准确度
- double可以承接18位左右有效数字
- 尽量减少除法,转换成乘法
- 尽量减少会导致误差的计算的次数
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
int main(){
ll N;
double S, avg = 0;
cin >> N >> S;
int A[500005];
for(int i = 0; i < N; i++)
cin >> A[i];
avg = S*1.0/N;
sort(A, A+N);
double ans = 0;
for(int i = 0 ; i < N; i++){
if(A[i]*(N-i) < S){
ans += (avg - A[i]) * (avg - A[i]);
S -= A[i];
}
else{
double cur = S*1.0/(N-i);
ans += (cur-avg)*(cur-avg)*(N-i);
break;
}
}
printf("%.4lf", sqrt(ans/N));
return 0;
}