本文作者:大家好,我是原始豌豆,欢迎来到牛客网刷题解析第五期,感谢你阅读本文欢迎评论,收藏,点赞哦。
内容专栏:这里是《牛客网在线编程》专栏,笔者用重金(时间和精力)打造,每道题目提供多种解法,从基础到拓展,希望可以帮到读者们。
写作不易:本文对每道题目提供了多种解法并加上了详细的注释,意在帮助读者锻炼思维灵活性,提高分析、解决问题的能力)。
开端
本次更新,全篇共一万多字,详细解析了每道题目,对其中一些题目采用了多种解法,并详细讲解了其中蕴含的算法思想和数学公式,在这篇文章中,我将分享刷题过程中的一些感悟、技巧和策略。同时,我也会分享一些个人的学习心得和经验,希望能帮助到同样热爱编程的你。
题目目录
牛客网语法篇基础语法81~100题(C语言实现)
本次更新在基础语法81~100题之间进行了筛选,挑选了一些题目讲解
♀️️️♀️️♂️⛹️♂️⛹️♀️♀️♂️
题目网址链接请点这✌️
标注“ * ”符号的题目为重点题目(“ * ” 数越多,难度越高)
本页目录跳转请点下方
BC81 KiKi求质数个数
BC85 牛牛学数列3
BC86 牛牛学数列
BC88 魔法数字转换 *
BC90小乐乐算多少人被请家长 *
BC91 水仙花数
BC92 变种水仙花数 *
BC93 公务员面试
BC95 小乐乐与进制转换 *
BC96 [NOIP2015]金币**
BC97 回文对称数**
BC99 正方形图案 *
BC100 直角三角形图案 *
解法一
思路 :质数(只能被1和他自身整除的数),先通过外层循环产生100-999之间的数。用这些数去时除以2到自身减1个数,如果能整除,就说明这个数不是质数,并将标志位flag设为0。
然后跳出内层循环,继续运行,因为flag被置为0,所以count不会自增。如果不能被2到自身减1个数整除,flag仍为1,count++。
//解法一
#include
int main() {
int count = 0;//计数器,用于记录素数的数量
int flag = 0; // 标志位,用于判断一个数是否为素数
for (int i = 100; i <= 999; i++) {
flag = 1;//默认是素数
for (int j = 2; j < i;j++) {//判断素数只需要判断到SQRT及之前的数即可
if (i % j == 0) {//有能被整除的数
flag = 0;// 不是素数,将标志位设为0并跳出内层循环
break;
}
}
if (flag)
count++;
}
printf("%d", count);
return 0;
}
解法二
该解法是对解法一的改造,因为除了2之外,所有偶数都不是质数,所以我们外层循环直接从101开始,并且每次+=2,跳过所有偶数,在101~999之间的奇数里寻找质数,这里内层循环j只需要循环到 i \sqrt[]{i} i 次即可,因为如果一个数不是素数,那么它必然有一个因子小于或等于它的平方根。
#include
#include
int main() {
int count = 0;//计数器,用于记录素数的数量
int flag = 0; // 标志位,用于判断一个数是否为素数
for (int i = 101; i <= 999; i+=2) {
flag = 1;//默认是素数
for (int j = 2; j <= sqrt(i);j++) {//判断素数只需要判断到SQRT及之前的数即可
if (i % j == 0) {//有能被整除的数
flag = 0;// 不是素数,将标志位设为0并跳出内层循环
break;
}
}
if (flag)
count++;
}
printf("%d", count);
return 0;
}
解法一
将分母不断变化的值和每项分式的值存放在两个变量里不断迭代和累加
#include
int main() {
double n = 0;
double sum=0,tmp = 0;
int flag = 1;//定义一个整数flag,用于控制序列中项的符号,初始化为1。
scanf("%lf", &n);
for (int i = 1; i <= n; i++) {
tmp+=(2*i-1)*flag;//tmp随着循环存放的是每项分母的值,不断增加
sum+=1.0/tmp;//sum里存放的是每项分式的值
flag = -flag;//改变flag的值,这样在下次迭代时,交错序列的符号就会改变。
}
printf("%.3lf", sum);
return 0;
}
解法二
1+1/(1-3)+1/(1-3+5)+…+1/(1-3+5-…((-1)^(n-1))*(2n-1)),该数列第二项化简等于-1/2,第三项等于1/3,第四项等于-1/4依次递推,该数列最终化简为:1-1/2+1/3-1/4+1/5-1/6+·····+1/n;
#include
int main() {
double n = 0;
double sum = 0, tmp = 0;
int flag =
1;//定义一个整数flag,用于控制序列中项的符号,初始化为1。
scanf("%lf", &n);
for (int i = 1; i <= n; i++) {
sum += 1.0 / i * flag; //sum里存放的是每项分式的值
flag = -flag;//改变flag的值,这样在下次迭代时,交错序列的符号就会改变。
}
printf("%.3lf", sum);
return 0;
}
//此题目有多种解法
解法一
//解法一 tmp随着循环存放每项的值,sum存放每项累加的值。
#include
int main() {
double n = 0;
int sum = 0, tmp = 0;
scanf("%lf", &n);
for (int i = 1; i <= n; i++) {
tmp = tmp + i;
sum = sum + tmp;
}
printf("%d", sum);
return 0;
}
解法二
观察数列可以发现
1出现了n+1-1次;对所有的1求和=1 × \times ×(n+1-1);
2出现了n+1-2次;对所有的2求和=2 × \times ×(n+1-2);
3出现了n+1-2次;对所有的3求和=3 × \times ×(n+1-3);
…
n出现了n+1-n次;对i求和=n × \times ×(n+1-n);
计算数列中所有1的值+所有2的值+…+所有n的值的结果就是答案
#include
int main() {
int i, n, sum = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
sum += (i * (n + 1 - i));
printf("%d", sum);
}
解法三
1+(1+2)+(1+2+3)+…+(1+2+3+…+n)可以转换化简为为下式
include <stdio.h>
int main() {
int n = 0;
scanf("%d", &n);
int res = n * (n + 1) * (n + 2) / 6;//此式的结果即为数列结果
printf("%d", res);
}
解法一
#include
int main() {
int a, b, n;
int count = 0;
scanf("%d", &n);
while (n != 1) {
if (n % 2 == 0) {
n = n / 2;
count++;
} else {
n = n * 3 + 1;
count++;
}
}
printf("%d", count);
return 0;
}
解法一
思路:使用一个外部循环,从1迭代到2019。对于外部循环中的每个数字i,使用一个内部循环来检查它的每一位数字。内部循环j从i开始,并逐渐减小j的值,直到j为0。在内部循环中,检查j的当前值对10取余的结果是否为9。如果是,这意味着j的当前位置的数字是9。在这种情况下,将count增加1,并使用break语句跳出内部循环。
#include
int main() {
int a, b;int j=0;
int count = 0;
for (int i = 1; i <= 2019; i++) {
for( j=i;j!=0;j/=10)//j不断变小
{
if (j % 10 == 9) { //个位、十位、百位取余结果若为9,则是我们需求的数字
count++;//符合情况,计数+1
break;
}
}
}
printf("%d",count);
return 0;
}
解法一
思路:创建两个for循环,外层控制班级人数,内层控制成绩三个一组的进行读取,三科成绩加起来大于180,则此同学平均分>=60,不用被请家长
nt main() {
float C;
float sum = 0;
int M = 0, n = 0;//M表示被请家长的同学人数
scanf("%d", &n);
for (int i = 1; i <= n ; i++) {
sum = 0;
for (int j = 0; j < 3; j++) {
scanf("%f", &C);
sum += C;//将变量C加到sum上。
}
if (sum < 180)//检查sum是否小于180。如果是,将变量M增加1。
M++;
}
printf("%d", M);
return 0;
}
解法一
思路:对于范围内的每一个数字 i,通过取模和整除操作获取其个位、十位和百位数字。然后,计算这三个数字的立方和,存储在变量 j 中。如果 j 等于原始数字 i,则 i 是一个水仙花数。
#include
#include
int main() {
int m, n, j, k;
while (scanf("%d %d", &m, &n) != EOF) {
k = 0;
for (int i = m; i <= n; i++) {//遍历从 m 到 n 的所有整数。
//取 i 的个位、十位和百位数字,计算它们的立方和,并将结果存储在变量 j 中。
j = pow(i % 10, 3) + pow(i / 10 % 10, 3) + pow(i / 100, 3);
if (j == i) {
printf("%d ", i);
k++;
}
}
if (k == 0)
printf("no\n");//如果在给定范围内没有找到任何阿姆斯特朗数,程序会打印 "no"。
}
return 0;
}
解法一
思路:对于范围内的每一个数字 i,通过取模和整除操作获取其个位、十位和百位,千位,万位数字。然后,计算这每个数字的立方和,存储在变量 i中。如果 每个数字的立方和 i等于初始的i值,则 i 是一个水仙花数。
#include
int main() {
int a, b, c, d, e;
for (int i = 10000; i <= 99999; i++) {
if (((i / 10000) * (i % 10000) + (i / 1000) * (i % 1000) + (i / 100) *(i % 100) + (i / 10) * (i % 10)) == i) {
printf("%d ", i);
}
}
return 0;
}
解法一
解题思路 1.可以通过对比找出最高成绩和最低成绩,然后将七个成绩相加再减去max和min求平均值。 多组输入上采用计数器控制每七个完事就重置
#include
int main() {
int score = 0, count = 0;
int max = 0, min = 100, sum = 0;
while (scanf("%d", &score) != EOF) {
sum += score;
if (score > max)//判定最高分//不要用if else 结构,会出错
max = score;
if (score < min)//判定最低分
min = score;
count++;计数器
if (count == 7) {//计数器=7时代表一组的分数好了可以进行计算
printf("%.2f\n", (sum - max - min) / 5.0);
sum = 0, max = 0, min = 100, count = 0;//重置
}
}
return 0;
}
解法一
解题思路 对于转换进制,一般用短除法。
短除法演示:
如十进制120 —> 六进制
120/6=20 ----余0
20/6=3 ----余2
3/6=0 ----余3 //直到商为0时,短除法结束
很明显所对应的六进制数为320,即为所得余数倒序,
#include
int main() {
int n, i = 0, num[50], j;//创建变量n用于接收输入的数字,i为数组下标。为了改变余数顺序,所以采用数组
scanf("%d", &n);
while (n / 6 != 0) {
num[i] = n % 6;//将每次得到的余数存放在数组里
n = n / 6;
i++;数组下标自增
}
printf("%d", n);
for (j = i-1 ; j >= 0; j--)//i为转换后的六进制数字个数,i-1是数组中存放元素的最后位置,倒序遍历数组
printf("%d", num[j]);
return 0;
}
解法二
采用递归,逆序短除法得到的余数
#include
void print(int x) {
if (x > 5) {
print(x / 6);
}
printf("%d", x % 6);
}
int main() {
int n = 0;
scanf("%d", &n);
print(n);
return 0;
}
解法三
通过余数乘对应的权数,右向左累加
#include
int main()
{
long n,sum=0,i=1;
scanf("%ld",&n);
while(n)
{
sum+=n%6*i;//收集每次%到的数,i代表位,i=1是个位,等于10是十位
n/=6;//除6
i*=10;//下一位
}
printf("%ld",sum);
return 0;
}
解法一
金币数 1x1+2x2+3x3x3+4x4x4x4+·····+nxn //一个1,两个2,三个3
第几天 1 2 3 4 5 6 7 8 9 10
每天金币数 1 2 2 3 3 3 4 4 4 4
天数 1 2 3 4 n
只需将天数累加起来
计算在前K天里,骑士一共获得了多少金币。只需要计算k可以拆成多少个天数累加起来,并且每个天数乘以本身所对应的金币数。
假设发6天,就可以拆成1+2+3,金币数就是1x1+2x2+3x3
假设发5天,假设拆成1+2+3+···的形式,比实际天数多加了一天,
用1x1+2x2+3x3-((1+2+3)-5)x3就是我们实际获得的金币
#include
#include
int main() {
int k = 0;
scanf("%d", &k);
int i = 1, j = 0, sum = 0;
while (sum < k) {
sum += i;
j += i * i;
i++;
}
sum = sum - k;
j -= sum * (i - 1);
printf("%d", j);
}
解法一
对每个数进行检验,检验方法为将该数反写,比较两数是否相同,相同则为回文数。
#include
int main()
{
int n;
scanf("%d", &n);
int i = 0;
for(i = 1; i <= n; i++)
{
int t = 0, num = i;
while(num > 0)
{
t = t*10 + num % 10;
num = num / 10;
}
if(t == i)
printf("%d\n", i);
}
return 0;
}
解法一
三层while循环,最外层控制多组输入,第二层控制行数,第三层控制列数
#include
int main() {
int a, b, i, j;
while (scanf("%d", &a) != EOF) {
i = 0;
while (i < a) {
j = 0;
while (j < a) {
printf("*");
j++;
}
printf("\n");//注意每打印完一行,要换行
i++;
}
}
return 0;
}
解法一
三层for循环,最外层控制多组输入,第二层控制行数,第三层控制列数
#include
int main() {
int n;
for (; scanf("%d", &n) != EOF;)//不用写初始化和调整部分。//for循环只跟一条语句时不用加括号
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)//for循环只跟一条语句时不用加括号
printf("* ");
printf("\n");
}
return 0;
}
解法一
三层循环,最外层控制多组输入,第二层控制行数,第三层控制列数
#include
int main() {
int a, b;
while (scanf("%d", &a) != EOF) {
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= i; j++)
printf("* ");
putchar('\n');
}
}
return 0;
}
总结:
** 本次筛选过的题目比往期明显增加了一些难度,刷题需要持之以恒的努力和耐心,只有不断地练习和总结,才能提高自己的编程能力和解决问题的能力。同时,也需要注重方法,选择合适的题目、理解题目、优化算法、测试和调试、总结和反思都是非常重要的步骤。