先介绍一下我的个人背景:本人大一,二本院校普通学生一枚。暑假看视频学完c语言,去年9月到今年3月利用空闲时间学了递归回溯,dfs, bfs, 快排归并, dp和贪心基础,数据结构的链表,栈和队列(因为bfs不得不学),进制转换,大数加减,欧几里得,素数筛等等。刷的题不是很多,经常一个晚上只能做一道题,资质一般。应该能代表大部分比较努力学习算法,不想荒废大学时光的大学生了吧。
参赛感想:考试前一周做了前两届蓝桥杯的省赛题目,感觉压力比较大,题意都看不懂。。。于是带着一个起伏不定的心理进了赛场。但总体感觉这一届蓝桥杯题目比历届水一点,题意很明确,题目没有历届灵活,很多题一看就知道怎么做。不过第一次参加,患得患失还是比较严重,前两道就花了一个小时仔细找坑。。这次做了8道,二叉树和最后一道没做,目前已知的错了两道,应该无缘国赛了吧。。 ok,下面上题目。
题意就是从以下队员挑选到1-5号位,每个队员只能选择一次。因此只需要选出每一列排前三的分数,自己再组合一下,找到最优解就行。17号贼强,1,3,4号位都是第一,但17号只能选择一次。知道题意后就是小学奥数题,手算就行。如果写代码,就是dfs暴力枚举了。
答案:490(有多组解)
26进制,可以计算器算,也可以直接拉excal表(上面的字母排列就是26进制)
答案:BYQ
第一反应是变形的斐波那契数列大数据,大整数加法。不过要求到第千万项,用大数加法时间复杂度太大。我列了前50项,用后四位加了一下测试了几个例子,发现其实就是计算后四位就行了。数据太大,不能用数组存,用几个变量迭代下去就行。直接上代码吧。
#include
using namespace std;
int main()
{
int a = 1, b = 1, c = 1, tmp;
for(int i = 4;i < 20190350;i++)
{
tmp = c;
c = a + b + c;
c %= 10000;
a = b;
b = tmp;
if(i > 20190300) printf("%d - %d\n",i, c);
}
return 0;
}
请记住:正整数不包括0,正整数包括0 。
其实只需要两层循环枚举a和b,然后算出c,判断c是否是正整数并且不包含2,4就行。最后枚举的计数除以6就是答案。
为什么除以6呢?
拿12举例,1,3,8这一组数据出现了6次,因此就除以6呗。。
#include
using namespace std;
int is(int x)
{
while(x)
{
if(x%10 == 2 || x%10 == 4) return 1;
x /= 10;
}
return 0; //包含2,4
}
int main()
{
const int n = 2019;
int a, b, c, ans = 0;
for(a = 1;a <= n;a++)
{
if(is(a) && a != 0) continue;
for(b = 1;b <= n;b++)
{
if(is(b) && b != 0) continue;
c = n-a-b;
if(is(c) && c != 0) continue;
if(a == b || b == c || a == c || c <= 0) continue;
// cout<
ans++;
}
}
cout<<ans/6<<endl;
return 0;
}
答案:40785
其实就是一道典型的bfs问题,字典序的条件只需要调整一下遍历的优先方向就行。比赛的时候因为迷宫数据太大,输出路径的时候程序总是闪退,优化了1个小时 由于暂时没有文档,因此只能演示一下样例。
#include
#include
#include
using namespace std;
char a[32][52];
typedef struct
{
int x;
int y;
int pre; //存放父结点的编号
char turn;
}node;
typedef struct
{
node data[1000]; //存放结点的队列
int front; //队列头部
int rear; //队列尾部
}Queue;
void print(Queue qu, int cur) //获取该队列和当前结点的参数,由于要倒序输出,因此用递归(调用栈)
{
while(qu.data[cur].pre != -1)
{
printf("%c",qu.data[cur].turn);
cur = qu.data[cur].pre;
}
}
void path(int xi, int yi, int xe, int ye) //从(xi,yi)走到(xe,ye)
{
int ok = 0;
Queue qu; //创建队列
qu.rear = 0; //初始化队列
qu.front = -1;
qu.data[0].x = 0;
qu.data[0].y = 0;
qu.data[0].pre = -1; //初始结点的pre设为-1,作为输出路径的递归出口
qu.data[0].turn = '*';
a[xi][yi] = '2'; //表示该结点已经遍历过
while(qu.front != qu.rear && ok == 0) //若队列不为空 (队列为空表示所有能扩展的结点都扩展完了也没能发现目标结点,表示无解)
{
qu.front++; //出队,front指向出队结点
if(qu.data[qu.front].x == xe && qu.data[qu.front].y == ye) //若出队的结点是目标结点
{
ok = 1;
print(qu, qu.front); //根据该结点反推到初始结点并输出
}
else
{
int k;
char t;
int i = qu.data[qu.front].x, j = qu.data[qu.front].y;
for(k = 0;k < 4;k++) //循环4次,扩展该出队结点
{
i = qu.data[qu.front].x, j = qu.data[qu.front].y;
switch(k)
{
case 0: i++;t='D'; break;
case 1: j--;t='L'; break;
case 2: j++;t='R'; break;
case 3: i--;t='U'; break;
}
if(a[i][j] == '0' && i >= 0 && i <= xe && j >= 0 && j <= ye) //扩展结点可用
{
// printf("%d\n",k);
qu.rear++; //将扩展的结点进队并初始化进队结点的坐标和并将pre设为父结点的编号(之后可通过pre找到父结点)
qu.data[qu.rear].x = i, qu.data[qu.rear].y = j;
qu.data[qu.rear].pre = qu.front;
qu.data[qu.rear].turn = t;
a[i][j] = '2'; //表示该结点已经遍历过,避免后面重复遍历
}
}
}
}
if(ok == 0) printf("无解。\n");
}
int main()
{
int i, j, n = 30, m = 50; //初始化迷宫
memset(a, '*',sizeof(a));
for(i = 0;i < n;i++)
{
for(j = 0;j < m;j++)
scanf("%c",&a[i][j]);
getchar();
}
path(0,0,n-1,m-1);
return 0;
}
挺简单的一道分离数字的题,不知道有什么坑。。。(不管,样例过了就是过了)
#include
using namespace std;
int is(int x)
{
while(x)
{
if(x%10 == 2 || x%10 == 0 || x%10 == 1 || x%10 == 9) return 1;
x /= 10;
}
return 0;
}
int main()
{
int i, n;
long long ans = 0;
scanf("%d",&n);
for(i = 1;i <= n;i++)
{
if(is(i)) ans += i;
}
printf("%lld\n",ans);
return 0;
}
读懂题意后第一反应就是找公约数。找每个数之间的最大公约数(求最短项),在每个公约数里面找公约数最小的(包括给出的所有整数),gcd,欧几里得嘛。之后将总项算出来就行。不过可能会有些坑是我没注意的。上代码:
#include
#include
using namespace std;
int gcd(int a, int b)
{
if(b == 0) return a;
return gcd(b, a%b);
}
int main()
{
int i, n, max_num = -1, min_num, min_gcd;
int a[100010], ans = 0, tmp, flag = 0;
scanf("%d",&n);
for(i = 0;i < n;i++)
{
scanf("%d",&a[i]);
if(i == 0)
{
max_num = a[0];
min_num = a[0];
}
else
{
if(a[i] == a[i-1]) flag = 1;
tmp = gcd(a[i], a[i-1]);
if(min_gcd > tmp) min_gcd = tmp;
max_num = max(a[i], max_num);
min_num = min(a[i], min_num);
}
}
if(flag) ans = n;
else ans = (max_num-min_num)/min_gcd + 1;
printf("%d\n",ans);
return 0;
}