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';//4430091return 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;
}