填空题2 (5') ps2020年门牌制作和这一题很像,几乎解题思路相同
涉及到 的知识点:枚举,十进制拆分
#include<bits/stdc++.h>
using namespace std;
//typedef long long ll;
int nums[10];//全局变量定义数组 nums[10]={1,2,3,4,5,6,7,8,9,0}
bool check(int x){
while(x){
int a=x%10;//取个位数
if(nums[a]>0) nums[a]--;
else return false;
x/=10;//除去个位数 保留十位
}
return true;
}
int main(){
int i;
for(i=0;i<=9;i++){
nums[i]=2021;
}
for(i=1; ;i++){
if(!check(i)){
cout<<i-1<<endl;//当这个数是y时不成立,卡片已用完,则该数-1;
break;
}
}
return 0;
}
答案:3181
如何验证:用excel,word文档
将excel里面的3181个数用依次相差1的方式增大,并复制到word 用替换查找1的换成A可观察到1 替换了2021次,其他数字替换可能没到2021,但可以看出题目已经到了最大(3182不行)
再做的缺点:函数不会写,i-1 每怎么理解到
2020年门牌制作
#include<iostream>
int nums[10];
using namespace std;
int shu(int x){
int ans;
while(x){
int a=x%10;
if(a==2) ans++;
x=x/10;
}
return ans;
}
int main()
{
int i,a=0;
for(i=1;i<=2020;i++){
a+=shu(i);//老忘了每个单独函数都是对一个数进行函数计算 忘记+
}
cout<<a;
return 0;
}
填空题3 (10‘)
涉及知识点:枚举、浮点数判
#include<bits/stdc++.h>
using namespace std;
struct point{
duuble x,y;
}p[25*25];
map<pair<double,double> ,int> mp;
int main(){
int cnt = 0;
for(int i=0;i<20;i++){
for(int j=0;j<21;j++){
p[cnt].x=i;
p[cnt].y=j;
}
}
int ana=20+21;
for(int i=0;i<cnt;i++){
for(int j=0;j<cnt;j++){
if(p[i].x==p[j].x||p[i].y==p[j].y)
continue;
double k=(p[i].y-p[j].y)/(p[i].x-p[j].x);
double b=(p[j].x*p[i].y-p[i].x*p[j].y)/(p[i].x-p[j].x);
if(mp[{k,b}]==0){
mp[{k,b}]=1;
ans++;
}
}
}
cout<<ans<<endl;
return 0;
如何验证:将代码数据改小,画图自己实操对比
2021 编程训练
#include<iostream>
#include <iomanip>//使用stew一定要用这个
using namespace std;
int main(){
long long n;
cin>>n;//这个n是毫秒码
n/=1000;//对毫秒进行换算成秒 题目有说不考虑毫秒
n%=(24*60*60);//先把所有的数字都整除完除去时分秒(完整的一天),最后剩下的是不足一天的
cout.fill('0');//填充所有输出是填充为0
cout<<setw(2)<<n/3600<<":"<<setw(2)<<n/60%60<<":"<<setw(2)<<n%60<<'\n';
return 0;
}
这里有几个问题首先是cout 后面的fill为什么要这么加 还有setw(2)是什么意思
关于setw()和cout.width()::是一个字段宽度的设置,n表示宽度(仅对后面的输出有效,输出结束后恢复默认),若输出时默认为右对齐,若想要他们左对齐只需要插入 std:left.若输出的长度<n 则前面用空格补齐,当字段长度>n时,全部整体输出
setw()的头文件:#include<iomanip> io为标准的输入输出 manip是manipulation的缩写,是操纵的缩写
cout.fill() fill是用来填充空白部分的,但是与上面的不同,fill函数在设置后一直有效
而且输出的字符串:123456789
******* 123 //(注意星号和数字之间还有一个空格)
cout.fill() 与cout.width()配套使用
setwfill 与setw() 配套使用
2021 杨辉三角
这里应该最大不超过16行,这里的k是表示列 2k表示行,这里的res更像是在一列中进行二分后得到的,最后输出第几个数=(首相+末项)x项数÷2+列数+1(因为从0开始计算)
对于函数我不知道不理解
可以手动模拟是对的,
涉及到二分法用于找列数
#include<iostream>
#define int long long
using namespace std;
int n;
int C(int a,int b){//why
int res=1;
for(i=a,j<1;i<=b;i--,j++){
res=res*i/j;
if(res>n)return res;
}
return res;
}
signed main(){
cin>>n;
for(int k=16;;k--){
//这里是进行二分法
int left = 2*k,right=max(n,1),res=1;
while(left<=right){
int mid=(left+right)/2;
if(C(mid,k)>=n) res=mid,right=mid-1;
else left=mid+1;
}
if(C(res,k)==n)return cout<<(res+1)*res/2+k+1<<'\n',0;
}
return 0;
}
2020c/c++蓝桥杯B组
检查:改小这个数 2020改成5
#include<inostream>
using namespace std;
int gcd(inta,int b){
if(a%b==0) return b;
else return(gcd(b,a%b));
}
//说真的不会这个函数,但是手动模拟了一下好像明白了为什么返回值一定为1
signed main(){
int i,j,ans = 0;
for(i=1;i<=2020;i++){
for(j=0;j<=2020;j++){
if(gcd(i,j)==1) ans++;
}
}
count<<ans<<endl;
return 0;
}
最大公约数的算法:参考文
辗转相除法:
int measure(int x,int y)
{
int z=y;
while(x%y!=0)
{
z=x%y;
x=y;
y=z;
}
return z;
}
递归法
int gad(int x,int y)
{
if(y==0) return x;
else return gac(y,x%y);
}
蛇形填数
有两种方法:1.手动模拟,可以建立一个表格进行模拟到20行20列
2.编程,但是建议先可以尝试4*4以内的进行模拟,找到行于列之间的关系
20行20列对应的对角线一共有39条,但我们要算到第38条,最后在加上20,这个可以通过4列4行的来模拟 (1+38)*38/2+20=761;
编程:找出行和列之间的关系:
r行 c列 ans记录次数,ans的最后值为最终答案
当r=1,c为奇数 (r,c+1)
当r=1 ,c为偶数 (r+1,c-1)
当c=1 ,r为偶数 (r+1,c)
当c=1 ,r为奇数 r!=1 (r-1,c+1)
若c!=1,r!=1,则(r+c)为奇数(r+1,c-1)
当c!=1,r!=1 ,(r+c)为偶数 (r-1,c+1)
#include<iostream>
using namespace std;
int main(){
int r=1,c=1,ans=1;
while(r!=20||c!=20){
if(r==1){
if(c&1) c++;//c为奇数
else r++,c--;//注意这里用到了,
}
else if(c==1){
if(r%2==0) r++; //c为偶数
else r--,c++;
}
else if((r+c)%2) r++,c--;//注意这里的if是0 为假
else r--,c++;
ans++;//每走一步都要++,记录步数
}
cout<<ans<<'\n';
return 0;
}
跑步训练
分析:if是月初或者是周一则跑两千米,但这中间也有一个隐形的条件(同时是月初或周一,单独是月初或者周一) 用excel表格的函数可以实现列表
首先输入2000/1/1 然后拖长填充到2020/10/1 其次用函数日期和时间中weeday 输入,根据提示输入6,和计数方式 第三列判断是否满足周一和月初用逻辑函数or ,第四列判断跑2km还是1kmif true第三列就输出2,else 输出1
最终计算跑步一共跑了多少sum,选中D列就有出现sum值=8879
法二:编程:涉及到月份要用闰年和平年,还有月份的总天数判断以及星期数
#include<iostream>
using namespace std;
int D[13]//对应的月数
bool check (int x){
if(y%400==0||(y%4==0&&y%100!=0)) return false;
else reture false;
}
signed main(){
D[1]=31,D[2}=28,D[2]=31,D[3]=31,D[4]=30,D[5]=31,D[6]=30,D[7]=31,D[8]=31,D[9]=30,D[10]=31,D[11]=30,D[12]=31;
int ans=0,week=6;
for(int y=2000;y<=2020;y++){
if(check(y)) D[2]=29;
else D[2]=28;//对年份的重置
for(m=1;m<=(y==2020?10:12;m++){//注意这里的y是要<=2020的这个月数
if(y==2020&&m==10)D[m]=1;
for(int d=1;d<=D[m];d++){
if(weel==1||d==1) ans+=2;
else ans+=1;
week=(week+1)%7;//计算星期数的方式只是0表周天,6表周六
}
}
}
cout<<ans<<"\n";
return 0;
}
与这个题目类似的
回文日期
这道题和回文字符串很相似,又和栈很相似
题目描述
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
输入描述
输入包含一个八位整数 NN,表示日期。
对于所有评测用例,10000101 \leq N \leq 8999123110000101≤N≤89991231,保证 NN 是一个合法日期的 8 位数表示。
输出描述
输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。
输入输出样例
示例
输入
20200202
输出
20211202 21211212
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
#include <iostream>
using namespace std;
bool isLeap(int y){
return (y%4==0&&y%100!=0)||(y%400==0);
}
bool check(int year,int month,int day){//判断是否为合法日期
if(month>12||month==0) return false;
if(day>31) return false;
if(month==2){
if(isLeap(year)&&day>29)
return false;
if(!isLeap(year)&&day>28)
return false;
}
if(month==4||month==6||month==9||month==11){
if(day>30) return false;
}
return true;
}
int main()
{
int n,i;
cin>>n;
int a,b,c,d,e,f,g,h;//8位数字
int year,month,day;
bool flag=false;
for(i=n+1;i<=99999999;i++){
year=i/10000;
month=(i%10000)/100;
day=i%100;
a=i%10;
b=(i/10)%10;
c=(i/100)%10;
d=(i/1000)%10;
e=(i/10000)%10;
f=(i/100000)%10;
g=(i/1000000)%10;
h=(i/10000000)%10;
if(a==h&&b==g&&c==f&&d==e&&flag==false){
if(check(year,month,day)){
cout<<i<<endl;
flag=true;//只输出一个回文
}
}
if(a==h&&b==g&&c==f&&d==e&&a==c&&b==d){
if(check(year,month,day)){
cout<<i<<endl;
break;
}
}
}
return 0;
}
第十四届蓝桥杯模拟赛 详细解答:https://blog.csdn.net/weixin_67596609/article/details/129384380
补充的蓝桥杯的知识:关于十六进制需要认识:十进制数转换成十六进制是 / 既是用短除法。
这里有简便方式:根据题目所知最小的数 且都是AAA 我们转换成十进制既是:10*16^2+10*16+10=2730.
#include<stdio.h>
int valid(int x){
while(x){
if(x%16>=10&&x%16<=15);//保证数字是在10和15之间才能形成A-F
else return 0;
x/=16;//注意这里是/16
}
return 1;
}
int main(){
for(int i=2023;i;i++){
if(valid(i){
printf("%d",i);
break;
}
}
return 0;
}
#include <stdio.h>
int main(){
int i; char ch;
for(i=2023;;i++)
{ int temp=i;
while(temp!=0)
{ ch=temp%16+'0';
if(ch<='9')break;
temp=temp/16; }
if(temp==0)
break;
}
printf("%d",i);
return 0;
}
这个答案最终是 2730
简单方法:直接用excel表格横向拖动到2022,看其所对应的字母。
计算方式:2022-6-26*26-26*26=644(第一次减26是减去的一个字符的,第二次减去26*26是减去两个字母的,第三次减去26*26是减去三个字母中第一个字母为A的情况,也就是到三个字母中第一个字母为B的情况BZZ)再次减去26*26=676,发现结果是-32,我们就倒回去寻找26+6=32;最后答案是BYT;
编程:这个不建议使用,由于没有办法确定是几位数的字母,至少来说我没有确定,有点没看懂
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int get(int x, int y, int z)
{
return x * 26 * 26 + y * 26 + z;
}
string str(int x, int y, int z)
{
string s;
s += 'A' + x - 1; //转换为字符形式
s += 'A' + y - 1;
s += 'A' + z - 1;
return s;
}
int main() {
int n = 2022;
for (int i = 1; i <= 26; i++)
for (int j = 1; j <= 26; j++)
for (int k = 1; k <= 26; k++)
if (get(i, j, k) == n)
{
cout << str(i, j, k);
return 0;
}
return 0;
}
方法:日期转换为8位数的数字,再去枚举19000101到99991213之间的每个数字。我们需要先判断该数字是否为合法日期
再去判断年份的数位数字之和是否等于月的数位数字之和加日的数位数字之和
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int res;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//这里的定义是31,且a[0]是0;
bool check_vaild(int year,int month,int day)
{
if (month == 0 || month > 12)//月
return false;
if (day == 0)//天
return false;
if (month != 2)//月
{
if (day > days[month])
return false;
}
else
{
int leap = year % 400 == 0 || year % 4 == 0 && year % 100;//年 天
//leap的书写很有意思,使判断闰年2月天数变得简单
if (day > days[month] + leap)
return false;
}
return true;
}
int main()
{
for (int i = 19000101; i <= 99991213; i++)//把所有的年月日合算起来做
{
int year = i / 10000;
int month = i % 10000 / 100;
int day = i % 100;
if (check_vaild(year, month, day))//先判断是否合法
{
int x=0, y=0, z=0;
for (int i = 0; i < 4; i++)
{
x += year % 10;
year /= 10;
}
while (month)
{
y += month % 10;
month /= 10;
}
while(day)
{
z += day % 10;
day /= 10;
}
if (x == y + z)//再进行加减
res++;
}
}
cout<<res;
return 0;
}
答案是:70910
上面的题有一道和这个解法相似
#include <iostream>
using namespace std;
bool isLeap(int y){
return (y%4==0&&y%100!=0)||(y%400==0);
}
bool check(int year,int month,int day){//判断是否为合法日期
//注意这里的所有返回都是false,只有最后返回的是true
if(month>12||month==0) return false;
if(day>31) return false;
if(month==2){
if(isLeap(year)&&day>29)
return false;
if(!isLeap(year)&&day>28)
return false;
}
if(month==4||month==6||month==9||month==11){
if(day>30) return false;
}
return true;
}
int main()
{
int n,i;
cin>>n;
int a,b,c,d,e,f,g,h;//8位数字
int year,month,day;
bool flag=false;
for(i=n+1;i<=99999999;i++){
year=i/10000;
month=(i%10000)/100;
day=i%100;
a=i%10;
b=(i/10)%10;
c=(i/100)%10;
d=(i/1000)%10;
e=(i/10000)%10;
f=(i/100000)%10;
g=(i/1000000)%10;
h=(i/10000000)%10;
if(a==h&&b==g&&c==f&&d==e&&flag==false){
if(check(year,month,day)){
cout<<i<<endl;
flag=true;//只输出一个回文
}
}
if(a==h&&b==g&&c==f&&d==e&&a==c&&b==d){
if(check(year,month,day)){
cout<<i<<endl;
break;
}
}
}
return 0;
}
这道题用暴力枚举解法还算是比较简单的
#include<stdio.h>
int main(){
a[31]={0,99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77};
int i,sum=0,res=0;
for(i=1;i<=30;i++)
for(j=1;j<=30;j++){
sum+=a[i]*a[j];
if(sum>=2022) res++;
}
printf("%d",res);
return 0;
}
对于这道题来说是编程的第一题,相对来说是比较简单,有人称之为签到题
#include<stdio.h>
int main(){
int n,m;
scanf("%d %d",&n,&m);
int mod=m%7;
for(int i=1;i<=mod;i++){//循环次数为mod次
if(n+1>7) n=1;
else n++;
}
printf("%d",n);
return 0;
}
时间复杂度O(mod);
下面的时间复杂度要小的多
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int w,n;
cin>>w>>n;
if((w+n)%7==0) cout<<'7'<<endl;
else cout<<(w+n)%7<<endl;//其实这个方法就很厉害了
return 0;
}
在函数distance上面没有读懂sqrt这样做的原因
#include<iostream>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<cmath>
#include<vector>
using namespace std;
int num[105][105]={0};
inline double distance (int x1,int y1,int x2,int y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));//这个地方没看太懂
}
int main(){
int w,h,n,R;
cin>>w>>h>>n>>R;
for(int i=0;i<n;i++){
int x,y;
cin>>x>>y;
for(int j=x-R;j<=x+R;j++){
for(int k=y-R;k<=y+R;k++){
if(j>=0&&j<=w;k>=0&&k<=H&&distance(x,y,j,k))
num[j][k]=1;
}
}
}
int count=0;
for(int i=0;i<=e;i++){
for(int j=0;j<=h;j++){
if(num[i][j]==1)
count++;
}
}
cout<<count<<endl;
return 0;
}
这道题的方法很暴力(没清理为1,清理为0,最终算多少没清理就相加)
#include<algorithm>
#include<string>
using namespace std;
int r1,c1,r2,c2;
int n,m,t;
int a[110][110];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=1;
}
}
cin>>t;
while(t--){
cin>>r1>>c1>>r2>>c2;//读懂题目很关键
for(int i=r1;i<=r2;i++){
for(int j=c1;j<=c2;j++){
a[i][j]=0;
}
}
}
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
res+=a[i][j];
}
}
cout<<res;
}
两个代码的意思是一样,但是下面的要简单的表达 (没清理的为0,清理为1),最后减去清理了的数目count剩下的为没清理数目)
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int num[105][105] = {0};
int main() {
int W, H, n;
cin >> W >> H >> n;
int count = 0;
for (int i = 0; i < n; i++) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
for (int j = x1; j <= x2; j++) {
for (int k = y1; k <= y2; k++) {
if (num[j][k] == 0) {
num[j][k] = 1;
count++;
}
}
}
}
cout << W * H - count << endl;
return 0;
}