1.5211: 18岁
你到18岁需要过几天,当然你的18岁生日还有可能不存在,比如你是今年2月29日出生的,那你每四年就只能过一个生日,18不是4的倍数,所以没生日可过。
我们用变量sum表示我们到18岁的天数,接下来就只需要解决闰年还有平年的问题了,你是3月出生的,那今年闰年和你无关啊,你是二月前才有关联,所以二月之后生日的你需要看的是下一年是不是闰年。也就是你的1岁生日不是因为你出生的那年是闰年就是366天,而是因为1.今年是闰年,而且你是3月前出生。2.明年是闰年,而且你是3月后(包含)出生
两个数字之间的-可以用一个char字符读入
#include <bits/stdc++.h> using namespace std; //判断闰年函数 bool isLeapYear(int y) { if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) return true; return false; } int main() { int T; cin >> T; while (T--) { int y, m, d; char c; //读入年月日,中间用char隔开 cin >> y >> c >> m >> c >> d; //总日子数sum int sum = 0; //2.29没生日输出 if (m == 2 && d == 29) { cout << "-1" << endl; continue; } //3月之后(包括)看下一年 if (m > 2) y++; //循环18年 for (int i = y; i < y + 18; i++) { if (isLeapYear(i)) sum += 366; else sum += 365; } cout << sum << endl; } return 0; }
2.1060: 鹊桥相会
这个题目看起来很复杂,但是需要自己不去关注那些无用的条件。因为喜鹊只能往一个方向飞,还想带着牛郎往织女方向飞,天和是正方向,所以喜鹊的位置必须是负数或牛郎所在的位置0,喜鹊的速度必须是正数才飞对了方向。之后就是路程s是w*1000-t(因为t是负数,减去变正数),速度是v,时间t=s/v,取最小即可
你可以估算一下最大时间,就是w=1000,t=1000,v=1,也就是10001000,我只要设置一个大于他的数就可以作为最大值了
#include <bits/stdc++.h> using namespace std; int main() { int w, n; while (cin >> w >> n, w || n) { //设置一个到达不了时间,也就是最大时间+1 int minTime = 10001001; while (n--) { int t, v; cin >> t >> v; if (t <= 0 && v > 0) { //时间=路程/速度 int time = (w * 1000 - t) / v; if (time < minTime) { minTime = time; } } } if (minTime == 10001001) cout << "Can't Solve "; else cout << minTime << " "; } return 0; }
我们可以先计算出商品总额,之后先使用满减优惠,再使用红包,使用需要注意自己的优惠券够不够,当然超过了不能不能支付负数
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while (T--) { int n, p, q, sum = 0; cin >> n >> p >> q; for (int i = 0,x; i < n; i++) { cin >> x; sum += x; } //discount优惠,表示满减优惠金额 int dis = (sum / 400) * 50; //可满减比拥有的少 if (p < dis) sum -= p; else sum -= dis; //使用红包优惠,金额比红包少 if (sum < q) sum = 0; else sum -= q; cout << sum << endl; } return 0; }
4.5857: 桃子的高低音
这个题目简单描述,就是一个高音就是他比两边的都高,那么我只要用每个数比较就好了,第一个和最后一个不会是高音
#include <bits/stdc++.h> using namespace std; const int N=1e5+5; int a[N]; int main() { int t; cin >> t; while (t--) { int n; cin >> n; for (int i = 0; i < n; i++) cin >> a[i]; int num=0; //两边均比中间大,满足统计 for (int i = 1; i < n - 1; i++) if (a[i] > a[i - 1] && a[i] > a[i + 1]) num++; cout << num << endl; } }
5.3016: 两圆位置关系
两圆的位置关系,和两圆点距离有关,关系如下:
学好编程之前一定要学好数学,加油~
但是距离算出来是一个浮点数,直接比较可能会出问题,我们直接对其进行平方,这样也不需要考虑谁大谁小了,不需要取绝对值了
#include <bits/stdc++.h> using namespace std; int main() { int x1, y1, r1; while (cin >> x1 >> y1 >> r1) { int x2, y2, r2; cin >> x2 >> y2 >> r2; int D = (r1 + r2) * (r1 + r2), d = (r1 - r2) * (r1 - r2); double len = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); int ans; //以下是if嵌套的,注意! if (D == len || d == len) { //两圆心距离与半径之和或之差相等 ans = 1; } else if (len > D) { //两圆心距离大于半径之和 ans = 2; } else if (len < d) { //两圆心距离小于于半径之差 ans = 3; } else { ans = 4; } cout << ans << endl; } return 0; }
6.5044: 在霍格沃茨找零钱
十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可。和时间是不是很像,1小时是60分,1分钟是60秒。这都属于进制转换题目,我们先取余,再取整抛弃这一位就可以了
#include <bits/stdc++.h> using namespace std; int main() { int p[3], a[3]; char b; cin >> p[0] >> b >> p[1] >> b >> p[2] >> a[0] >> b >> a[1] >> b >> a[2]; //应付的总纳特 int sum1 = p[0] * 17 * 29 + p[1] * 29 + p[2]; //实付的总纳特 int sum2 = a[0] * 17 * 29 + a[1] * 29 + a[2]; int sum = sum2 - sum1, ans[3]; //钱没带够先输出负号 if (sum < 0) { cout << "-"; sum = -sum; } //获取纳特数 ans[2] = sum % 29; //丢去纳特数 sum = sum / 29; //获取银西可数 ans[1] = sum % 17; //丢去银西可数 sum = sum / 17; //sum即为加隆数 ans[0] = sum; cout << ans[0] << "." << ans[1] << "." << ans[2] << endl; }
7.4020: 有道水题
获取每一位还是需要进制转换。但是也可以直接用字符串来做这个题目,记得减去字符0
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while (T--) { string s; cin >> s; int sum = 0; for (int i = 0; s[i]; i++) sum += s[i] - '0'; //sum1代表从第1位到这一位总和 //flag为0表示不存在 int sum1 = 0, flag = 0; for (int i = 0; s[i]; i++) { sum1 += s[i] - '0'; //直接除以2下取整会出问题 if (sum1 + sum1 == sum) { //存在结束循环 flag = 1; break; } } if (flag) cout << "YES "; else cout << "NO "; } }
8.5128: 就是要62
还是进制转换,2进制转10进制。11的二进制表示是1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1,也就是第i位要乘上2^(len-1)
获取每一位的进制转换我们是倒过来,这个我们可以正过来,保证*2的次数对就可以了
#include <bits/stdc++.h> using namespace std; int main() { string s; //读入要进行转换的字符串s cin >> s; //设置变量t去保存这个答案 int t = 0; for (int i = 0; s[i]; i++) { t = t * 2 + (s[i] - '0'); } cout << t << " "; }
之后我们要把十进制转换为一位的一位,这样会帮我们倒过来
#include <bits/stdc++.h> using namespace std; int main() { string s; //读入要进行转换的字符串s while (cin >> s) { //设置变量t去保存这个答案 int t = 0; for (int i = 0; s[i]; i++) { t = t * 2 + (s[i] - '0'); } int len = 0; //10^9就是1后面有9个0,是十位 int a[10]; while (t) { //存储当前位 a[len++] = t % 10; //丢弃当前位 t /= 10; } int num = 0; for (int i = 1; i < len; i++) { //是26,字符串被倒过来了 if (a[i - 1] == 6 && a[i] == 2) num++; //是62 if (a[i - 1] == 2 && a[i] == 6) num++; } cout << num << " "; } }
9.1091: JudgeOnline
这个题目就是判断字符,你可能会忘记了tab符' ',因为要读取空格,请整行读入
#include <bits/stdc++.h> using namespace std; int main() { string s; //有空格,直接getline while (getline(cin, s)) { for (int i = 0; s[i]; i++) { if (s[i] == '<') cout << "<"; else if (s[i] == '>') cout << ">"; else if (s[i] == ' ') cout << " "; else if (s[i] == ' ') cout << "	"; else cout << s[i]; } cout << " "; } }
10.5858: 桃子的游戏
题意其实也蛮简单的,就是三个人初始是x、y和z,之后每个时间+i,然后按照两个条件进行加减点数,但是是一个三重循环
第一重循环是T组,第二重是q组,第三重是t的枚举
记得使用long long,1e5+(1+1e4)/2*1e4超过了int
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; //有T组 while (T--) { int x, y, z; //读入三个初始值 cin >> x >> y >> z; int q; cin >> q; while (q--) { int n; //读入这次查询的时间 cin >> n; //用X、Y和Z代表他们的当前值,但是这个值会超过int long long X = x, Y = y, Z = z; for (int i = 1; i <= n; i++) { //每个人都可以得到i点 X += i, Y += i, Z += i; if (Y >= 3) { //小明给桃子3点 Y -= 3; X += 3; } if (Z >= 6) { //小强给桃子6点 Z -= 6; X += 6; } } //最后是否比两个人的大 if (X > Y && X > Z) cout << "Yes "; else cout << "No "; } } return 0; }
11.5265: 围棋入门
如果这个棋子是白棋,那么他周围这四个就有可能要被你输出。所以去找到所有的白棋,看看其是否要输出
还有一个事情很麻烦,就是边界,我们不能越界,那我们可以将其第0行第0列空出来
行号从小到大的顺序输出,如果行号相同,则按照列号从小到大的顺序,这个我们用一个数组去记录我们的答案
#include <bits/stdc++.h> using namespace std; int ans[25][25]; char s[25][25]; //定义方向数组dir int dir[4][2]={1,0,-1,0,0,1,0,-1}; int main() { //读入第一行,存储从s[1][1]开始 while(cin>>(s[1]+1)) { int n=19; for(int i=2;i<=n;i++) { //读入第i行,存储从s[i][1]开始 cin>>(s[i]+1); } //清空答案 memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { //枚举每一个棋子,是W,需要找四个棋子 if(s[i][j]=='W') { for(int k=0;k<4;k++) { int x=i+dir[k][0]; int y=j+dir[k][1]; //是.代表可以放置 if(s[x][y]=='.')ans[x][y]=1; } } } } //假设白棋已经被围住 int flag=1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { //枚举每一个坐标看是否需要输出,这样可以保证先行再列 if(ans[i][j]) { cout<<i<<" "<<j<<" "; flag=0; } } } if(flag)cout<<"YuYu Wins! "; } }
12.1437: Zigzag
是不是和蛇形矩阵有点像,但是这个题目需要自己去设计循环,是一样的斜线,但是这个题还有方向,对角线可能是从左下到右上,也有可能是右上到左下
所以我们还需要借助一个变量去控制现在是哪个方向
flag=1代表左下到右上,也是一开始的方向,flag=-1代表从右上到左下,然后让其循环
最后的右下角重新找规律输出
#include <bits/stdc++.h> using namespace std; int main() { int n, a[25][25]; while (cin >> n ,n) { int s = 1, flag = 1; //对角线和为i for (int i = 0; i < n; i++) { //左下开始是0 for (int j = 0; j <= i; j++) { //左下到右上填充,否则颠倒填充 if (flag == 1) a[i - j][j] = s++; else a[j][i - j] = s++; } flag = -flag; } //右下角,最后是2n-2 for (int i = n; i < n + n-1; i++) { //左下开始是n-i for (int j = i-n+1; j < n; j++) { cout<<j<<" "<<i-j<<" "; if (flag == 1) a[i - j][j] = s++; else a[j][i - j] = s++; } flag = -flag; } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (j != 0) cout << " "; printf("%-3d", a[i][j]); } cout << endl; } cout<<" "; } return 0; }
13.1438: 螺旋形
这个题目就麻烦了,之前你们没有见过,但是我们可以思考一下,每次我们都是四个操作,向右,向下,向左,向上,一圈一圈往里填。
#include <bits/stdc++.h> using namespace std; int main() { int n, a[25][25]; while (cin >> n, n) { //n是1没有四个方向特判掉 if (n == 1) a[0][0] = 1; else { //i和j代表当前要填充的坐标,now是当前要填的数,N是最大可以填的数字 int i = 0,j = 0, now = 1, N = n * n; //设置四个上下左右变量,代表当前所在位置 int U = 0, D = n - 1, L = 0, R = n - 1; while (now <= N) { //向右走,列++ while (j < R && now <= N) { a[i][j] = now++; j++; } //向下走,行++ while (i < D && now <= N) { a[i][j] = now++; i++; } //向左走,列-- while (j > L && now <= N) { a[i][j] = now++; j--; } //向上走,行-- while (i > U && now <= N) { a[i][j] = now++; i--; } //缩一圈,i和j各加1 i++,j++; //缩一圈,U到了下一行,D到上一行,L到下一列,R到前一列 U++, D--, L++, R--; //填充最后一个数 if (now == N) a[i][j] = now++; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (j != 0) cout << " "; printf("%-3d", a[i][j]); } cout << endl; } cout << " "; } }
这篇博客还有两种写法,你需要推算出下标所对应的数字或者按照循环的方式去解答
14.3297: 名侦探柯南-破解死亡讯息
需要读懂这个题目,拿到字符s[i]代表的是我们这一密码段有s[i]-'A'个字符,这s[i]-'A'个字符要进一步解码,变为数字求和
#include <bits/stdc++.h> using namespace std; int main() { string s; while (cin >> s) { for (int i = 0; s[i]; i++) { //sum为当点段解码,c代表当前密码段有几个 int sum = 0, c = s[i] - 'A' + 1; for (int j = i; j < i + c; j++) sum = sum + s[j] - 'A' + 1; cout << sum; //下一次访问i+c,因为还要执行i++,回退一个 i = i + c - 1; } cout << " "; } return 0; }
15.5168: 报时助手
一个比较复杂的模拟题,我们需要考虑各种情况,这个题目要先思考好在再动手
我只是提供一种代码实现,你也可以自己想一个思路去避所有可能产生的bug,从而AC题目
#include <bits/stdc++.h> using namespace std; string s[25] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; int main() { int m, n; cin >> m >> n; //m比20小,我们已经有了输出答案 if (m <= 20) cout << s[m]; else { //将其拆成20+(m-20)进行输出 cout << s[20] << " " << s[m - 20]; } //是整点直接输出 if (n == 0) { cout << " o'clock"; } else if (n <= 20) { //小于20直接输出 cout << " " << s[n]; } else if (n < 30) { //将其拆成20+(n-20)进行输出 cout << " " << s[20] << " " << s[n - 20]; } else if (n < 40) { //将其拆成30+(n-30)进行输出 cout << " thirty"; //n-30是0不能输出 if (n - 30) cout << " " << s[n - 30]; } else if (n < 50) { //将其拆成40+(n-40)进行输出 cout << " forty"; //n-40是0不能输出 if (n - 40) cout << " " << s[n - 40]; } else { //将其拆成50+(n-50)进行输出 cout << " fifty"; //n-50是0不能输出 if (n - 50) cout << " " << s[n - 50]; } cout << " "; return 0; }
16.5136: 隧道有多长
这个题目也不难,就是你需要统计一个字符串中间有多少个连续的'#',当然也会不存在,所以最小值这个特别注意
我们可以一重循环去统计
#include <bits/stdc++.h> using namespace std; int main() { string s; while (cin >> s) { //用mi和mx来记录答案,t来记录当前的长度 int mi = 0, mx = 0, t = 0; for (int i = 0; s[i]; i++) { //是'#'需要将隧道长度+1 if (s[i] == '#')t++; //其他需要统计答案的情况 //1.不是隧道 2.最后一个字符了 if (s[i] == '*' || s[i + 1] == 0) { //最小值不是0取小 if (mi) { //t也不是0才能更新 if (t) mi = min(mi, t); } else mi = t; //最大值不是0,取大 if (mx) { mx = max(mx, t); } else mx = t; t = 0; } } cout << mi << " " << mx << endl; } return 0; }
17.3212: Pig在哪里
这个题目也很简单,你需要判断连续的三个字符是不是pig
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while (T--) { int n; string s; cin>>n>>s; int num=0; //从可以访问i-2开始 for(int i=2;i<s.length();i++) { if(s[i-2]=='p'&&s[i-1]=='i'&&s[i]=='g') num++; } cout<<num<<" "; } return 0; }
18.3134: 渊子赛马修改版
课堂上贪心的一个扩展,这个题目还是有一定难度的,允许平局我就得考虑这把怎么要平局
1.最好的最差都可以,那就赢了2.渊子最好的马比对手差,直接用下等马输掉3.相等,如果最差的马太菜,输掉,否则平局
代码会比思想更直观些
#include<bits/stdc++.h> using namespace std; int a[10005],b[10005]; int main() { int n; while(cin>>n,n) { for(int i=0; i<n; i++)cin>>a[i]; //渊子的马从小到大排序 sort(a,a+n); for(int i=0; i<n; i++)cin>>b[i]; //对手的马从小到大排序 sort(b,b+n); //aL(a数组左端点)是渊子当前最差的马的下标 //aR(a数组右端点)是渊子当前最好的马的下标 //bL是对手当前最差的马的下标,aR是对手当前最好的马下标 int aL=0,bL=0,aR=n-1,bR=n-1; //ans代表当前的净胜场数 int ans=0; for(int i=0; i<n; i++) { if(a[aL]>b[bL]) { //渊子最差的马比对手的还好,直接比掉 aL++,bL++,ans++; } else if(a[aR]>b[bR]) { //渊子最好的马比对手的还好,也可以直接比掉 aR--,bR--,ans++; } else if(a[aR]<b[bR]) { //渊子最好的马比对手差,直接用下等马输掉 aL++,bR--,ans--; } else if(a[aR]==b[bR]) { //最好的马相等,那么我需要考虑一下 //渊子最差的马比对手好的马差了,算了,用差马输出了 if(a[aL]<b[bR])ans--; //如果相等呢,那就是渊子剩下的马全一样了,直接平局就行 //!!!这个平局很重要,没有净胜减少 aL++,bR--; } } //净胜场数为正,为0,为负分别对应三种情况 if(ans>0) cout<<"Win "; else if(ans==0) cout<<"Draw "; else cout<<"Lost "; } return 0; }
19.5725: 营养膳食
贪心,按照脂肪指数从高到低排序,这种种类还可以选择就选择,且只能选m个。
#include <bits/stdc++.h> using namespace std; const int N = 1005; struct T { int ai, bi; } a[N]; int num[N]; bool cmp(T a, T b) { return a.ai > b.ai; } int main() { int n, m, k; cin >> n >> m >> k; for (int i = 1; i <= k; i++) cin >> num[i]; for (int i = 0; i < n; i++) cin >> a[i].ai >> a[i].bi; //按照ai进行排序,先吃脂肪指数高的 sort(a, a + n, cmp); int sum = 0; //进来选食物 for (int i = 0; i < n; i++) { //当前类别可选 if (num[a[i].bi]) { //把脂肪指数加上 sum = sum + a[i].ai; //这种种类的少一份 num[a[i].bi]--; m--; if (!m)break; } } cout << sum; return 0; }
20.3457: 最小新数
又回到了之前的进制转换,你可以得到0~9出现的位数
这个题目也是贪心,你需要从小开始输出,但是你不能直接先输出0,一个数不能从0开始,所以你要先输出一个。
#include <bits/stdc++.h> using namespace std; int main() { string s; while(cin>>s) { //看0~9的出现次数 int a[10]={0}; for(int i=0;s[i];i++) a[s[i]-'0']++; //先输出一个非0最小数字 for(int i=1;i<10;i++) { if(a[i]>0) { cout<<i; a[i]--; break; } } //继续从0开始,从小到大输出 for(int i=0;i<10;i++) { while(a[i]) cout<<i,a[i]--; } cout<<endl; } return 0; }
21.6149: 因子个数排序
#include <bits/stdc++.h> using namespace std; int a[205]; //计算因子个数函数 int cal(int n) { //sqrt是浮点数,可能会有问题,+0.5不会出问题 int x = sqrt(n + 0.5); //因为你最多算到一半,算出来因子i,那么n/i也是 int s = 0; for (int i = 1; i <= x; i++) { if (n % i == 0) { //3*3=9,这种完全平方特殊处理下 if (i * i == n) s++; else s += 2; } } return s; } int cmp(int s, int t) { //分别计算两数因子数 int s1 = cal(s), s2 = cal(t); //相等,比较两个大小 if (s1 == s2) return s > t; return s1 > s2; } int main() { int n; while (cin >> n) { for (int i = 0; i < n; i++) cin >> a[i]; sort(a, a + n, cmp); for (int i = 0; i < n - 1; i++) cout << a[i] << " "; cout << a[n - 1] << " "; } return 0; }
22.3148: 按1的个数排序
#include<bits/stdc++.h> using namespace std; string s[100]; int cmp(string s,string t) { //分别找到两个字符串1的个数 int s1=0,s2=0; for(int i=0;s[i];i++) if(s[i]=='1')s1++; for(int i=0;t[i];i++) if(t[i]=='1')s2++; //1的个数相等,按照s和t字典序排序 if(s1==s2)return s<t; return s1<s2; } int main() { int n; cin>>n; for(int i=0;i<n;i++) cin>>s[i]; sort(s,s+n,cmp); for(int i=0;i<n;i++) cout<<s[i]<<endl; return 0; }