【蓝桥杯14天冲刺课题单】Day 1
1. 题目链接:19937 艺术与篮球
该题目的难点主要在20240413这个日期需要结束程序跳出循环。最开始将该输出ans的位置放在了for循环之外,此时的日期已经循环完了2024年所有的日期,则最后会统计多而导致结果错误。
AC代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int day_1[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//用数组预处理每月的天数
int day_2[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int sum_num[10]={13,1,2,3,5,4,4,2,2,2};//预处理每一个数字的文字笔画
bool check_year(int year) //判断闰年,便于选择月份
{
if((year%4 == 0 && year%100!=0)||(year%400 == 0))
return 1;
else return 0;
}
int main()
{
int ans=0,result=0,m,d,sum=0;
for(int y=2000;y<=2024;y++)
{
if(check_year(y) == 1)
{
for(m=1;m<=12;m++)
{
for(d=1;d<=day_1[m];d++)
{
sum=0;
result=(y*10000)+(m*100)+d;
while(result)
{
sum += sum_num[result%10];
result=result/10;
}
if(sum > 50) ans++;
if ((y == 2024) && (m >= 4) && (d >= 13))
{
cout<<ans;
return 0;
}//就是这一段输出的位置需要注意
}
}
}
else if(check_year(y) == 0)
{
for(m=1;m<=12;m++)
{
for(d=1;d<=day_2[m];d++)
{
sum=0;
result=(y*10000)+(m*100)+d;
while(result)
{
sum += sum_num[result%10];
result=result/10;
}
if(sum > 50) ans++;
if ((y == 2024) && (m >= 4) && (d >= 13))
{
cout<<ans;
return 0;
}//已知2024是闰年,此处可以不需要这个输出
}
}
}
}
}
这个方法有重复的代码,需要简化。
2.题目链接: 3491 幸运数
该题目为填空题,可以直接进行输出。
最开始的算法是将每一个数字进行拆分,算出位数,再进行判断是否为偶数位。接着判断该数的左右两边的和是否相等,最后进行个数统计。这里因为数字是从后往前分离的,且是偶数位,则可以先统计后面的,到一半的长度时停止,再换另一个计数器统计前一半。但测评结果是TLE。那么不能使用直接分离的方法。
TLE的枚举代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#pragma GCC optimize(2)
using namespace std;
int check_number(int num)
{
int ans=0;
while(num)
{
num=num/10;
ans++;
}
if(ans%2 == 0) return ans;
else return 0;
}
int main()
{
int result=0;
for(int i=10;i<=100000000;++i)
{
int sum_1=0,sum_2=0,half;
int number=i;
if(check_number(i) != 0)
{
half=check_number(i)/2;
for(int j=1;j<=half;j++)
{
sum_1 += number%10;
number /=10;
}
for(int j=1;j<=half;j++)
{
sum_2 += number%10;
number /=10;
}
if(sum_1 == sum_2) result++;
}
else continue;
}
cout<<result;
return 0;
}
根据蓝桥杯的官方题解,可以将数字转换成字符串,则可以用字符串相关的函数直接得出结果数字的长度,进而判断数字是否为偶数位。这个方法直接将时间复杂度从O(n)降到了O(1)。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int ans = 0;
for (int i = 1; i <= 100000000; ++i)
{
string s = to_string(i); //直接转换成字符串,便于统计数字长度,时间复杂度为O(1);
int n = (int)s.size();
if (n % 2) continue;
int l = 0, r = 0;
for (int j = 0; j < n; ++j)
{
if (j < n / 2) l += s[j] - '0';//字符转换为数字
else r += s[j] - '0';
}
if (l == r) ans++;
}
cout << ans << '\n';//4430091
return 0;
}
3. 题目链接:1600 平方差
根据条件,最大的数字不超过2021,则可以将1到2021的所有可能性枚举出来。
同时因为,用sum数组进行统计,只要满足1到2021之间这个条件的数字就存入数组,不用管是否为1个拆分方式;最后遍历数组,存了数字的数组就计数器加1。因为是开的全局数组可以不用memset数组为0。
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e7;
int sum[maxn];
int main()
{
int result,ans=0;
for(int i=1;i<=2021;i++)
{
for(int j=0;j<i;j++)
{
result=(i+j)*(i-j);
if(result>=1&&result<=2021) sum[result]++;
}
}
for(int i=1;i<=2021;i++)
{
if(sum[i]!=0)
{
ans++;
}
}
cout<<ans;
return 0;
}
!!一开始无思路的题
4. 题目链接:19732 小球反弹
首先根据题目, 将小球的运动方向拆解为x轴方向上的运动和y轴方向的运动。设小球在x轴方向的运动距离,y轴方向上的运动距离为
。根据勾股定理,小球每秒移动的距离
当小球 A 回到起点时,说明其在水平方向上的移动距离是长方形长度的偶数倍,在垂直方向上的移动距离是长方形宽度
的偶数倍。因为小球碰壁反弹的路径与原来的路径相同,那么相同的路径走了偶数倍。
假设从开始到结束,小球总共花费了t 秒,那么有:
,
同时需要满足: ,
由此,对 t 进行枚举,直至找到满足 15t 整除 343720且17t 整除 233333,和
均为偶数的 t。
最终求得答案为 1100325199.77
。
需要注意的是,所求答案需要保留两位小数,则距离的数据类型需要用double。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long int
bool check(ll a,ll b)
{
if((a % b == 0)&&((a/b)%2 == 0)) return 1;
else return 0;
}
int main()
{
ll x=343720,y=233333;
ll lx,ly;
double dis;
ll t;
for(ll i=1;;i++)
{
t=i;
lx=15*t;
ly=17*t;
if(check(lx,x) && check(ly,y)) break;
}
dis=sqrt(15*t*15*t+17*t*17*t);
printf("%.2lf",dis);
return 0;
}