1.
C 库函数double fmod(double x, double y)返回x除以y的余数。
fmod() 是 C 标准库 <math.h> 中的一个函数,用于计算两个浮点数相除的余数。这个函数返回除法操作的余数,其符号与被除数相同。
声明
下面是 fmod() 函数的声明。
double fmod(double x, double y)
参数
x:被除数,一个浮点数。y:除数,一个浮点数。
返回值
- 返回
x除以y的余数,其符号与x相同。 - 如果
y是 0,结果为未定义,可能会产生一个计算错误。
所以求一个double类型数据的小数部分,可以用fmod(double,1.0) !
2.
C 语言对结构体赋值的原生支持,
- 结构体赋值的本质:当你执行
Person temp = arr[start];时,编译器会把arr[start]这个结构体变量的所有成员(name[15]数组、height整数)逐字节复制到temp中;后续的arr[start] = arr[end];和arr[end] = temp;也是同理,相当于手动写了 “交换每个成员” 的代码,但编译器帮你简化了。 - 对比手动交换成员:你手动交换需要写:
而直接赋值的写法是编译器帮你封装了上述逻辑,代码更简洁,且结果完全一致// 手动交换两个Person的所有成员 // 1. 交换name数组 char nameTemp[15]; strcpy(nameTemp, arr[start].name); strcpy(arr[start].name, arr[end].name); strcpy(arr[end].name, nameTemp); // 2. 交换height int heightTemp = arr[start].height; arr[start].height = arr[end].height; arr[end].height = heightTemp;
所以只有结构体成员没有动态分配内存的指针,就可以像交换int类型变量一样交换结构体类型变量的值
3.
以下是几种常用的四舍五入方法:(默认只有1位小数,多位小数时可先*100扩大舍入后再/100.0)
- **round()
函数**:不管有多少位小数,都直接四舍五入为整数,返回浮点数类型。例如,round(2.5)结果为3.0,round(2.4)为2.0`。 printf格式化:使用%.0f输出时,会自动按四舍五入处理。- 强制类型转换(取整):使用
(int)(x + 0.5)可实现正数的四舍五入到整数。 - 指定小数位数:若要保留两位小数,可使用
round(x * 100) / 100.0。
要实现平均数四舍五入返回整数打印:
double average = ((double)total_time) / count; printf("%d %d\n", count, (int)round(average)); }4.
去掉一个最高分和最低分时,两种思路:
1. 贪心策略求出最高、最低分(无并列),记录下其索引,遍历时跳过该索引位置
2. 用qsort升序排列,遍历索引从1到 len-1位置的元素即可
5.
有一个大小count=5的数组,已经按分数排名1、2、3、4、5排列好,但是要求对分数相同的按排名相同输出,比如输出1、1、3、4、4这种?
思路:
- 初始化排名变量
rank=1,遍历数组从第 2 个元素开始; - 对比当前元素与前一个元素的分数:
- 分数相同 → 当前排名 = 前一个排名,rank不变!
分数不同 → 当前排名 = 当前位置(即更新// 打印并列排名的思路 ! int rank = 1; printf("%d %s %d %d\n", rank, arr[0].name, arr[0].score, arr[0].count); for (int i = 1; i < count; i++) { if (arr[i].score == arr[i - 1].score) { printf("%d %s %d %d\n", rank, arr[i].name, arr[i].score, arr[i].count); } else { rank = i + 1; printf("%d %s %d %d\n", rank, arr[i].name, arr[i].score, arr[i].count); } }rank=当前索引+1)
6.
已经成功把所有不重复的因数存入res数组,现在需要从这个数组中选出 4 个不同的元素求和,核心思路是通过多层循环枚举所有合法的 4 元素组合
假设你的 res 数组长度为 len(且 len >= 4,因为之前已经判断过因数数量≥4),枚举步骤如下: 第一层循环(i):遍历数组第一个元素的下标,范围是 0 到 len-4(因为后面还要留 3 个位置给 j、k、l); 第二层循环(j):遍历第二个元素的下标,范围是 i+1 到 len-3(必须在 i 之后,且留 2 个位置给 k、l); 第三层循环(k):遍历第三个元素的下标,范围是 j+1 到 len-2(必须在 j 之后,且留 1 个位置给 l); 第四层循环(l):遍历第四个元素的下标,范围是 k+1 到 len-1(必须在 k 之后); 对每一组 res[i]、res[j]、res[k]、res[l],计算它们的和,然后判断这个和是否能被原数 N 整除// 选不同的4个 for (int i = 0; i <= count-4; i++) { for (int j = i+1; j <= count - 3; j++) { for (int k = j+1; k <= count - 2; k++) { for (int l = k+1; l <= count - 1; l++) { int sum = res[i] + res[j] + res[k] + res[l]; if (sum % x == 0) return 1; } } } }注意题目是若正整数 N 可以整除它的 4 个不同正因数之和
a可以整除b,是b%a==0的意思而不是a%b==0
等价于b可以被a整除,b作被除数,a作除数!
若搞反了整除判断关系,会出现逻辑错误且不好排查!
7.
判断素数的写法,一定要能熟练快速写出:
几个注意点:
1 不是素数,如果x==1直接return 0
2 虽然是偶数,但它是素数(只有1和本身的因数),所以x==2直接return 1
除2以外的偶数都不是素数,直接return 0
从i=3开始遍历每个奇数(i=i+2)直到i<=sqrt(x),如果x能被i整除,不是素数,return 0
若前面都没有return,说明是素数,return 1
int isprime(char* s) { int x; sscanf(s, "%d", &x); if (x == 1) return 0; if (x == 2) return 1; if (x % 2 == 0) return 0; for (int i = 3; i <= sqrt(x); i=i+2) { if (x % i == 0) return 0; } return 1; }8.
文件操作:
分为文本文件、二进制文件,读/写,截断还是追加
去菜鸟教程截图过来!
另外复习一下fseek、和刷新文件流的用法
通过光标(文件流指针)计算文件长度的方法
常量 描述 SEEK_SET 文件的开头 SEEK_CUR 文件指针的当前位置 SEEK_END 文件的末尾先fseek(fp, 0, SEEK_END)把光标移动到文件末尾,然后用
int len=ftell(fp)获取当前光标到文件开头的距离,即文件长度
最后建议用fseek(fp, 0, SEEK_SET)把光标移回文件开头方便下一次操作
9.
因式分解用试除法,i从2开始到i=n结束(不要到sqrt(n)就结束),最后可能剩一个大质数,到i=自然会取到这个剩下的大质数!
void main(){ int n; scanf("%d",&n); int i=2; int temp=n; printf("%d=",n); while (i <= temp) { if(temp%i == 0){ printf("%d",i); temp=temp/i; if(temp!=1){ printf("*"); } } else{ i++; } } }10.
十进制小数转二进制时,用乘2取整法,如:
0.25 → 0.25×2=0.5(取 0) → 0.5(取结果的小数部分,若上一步结果为1.5,也是取0.5)×2=1.0(取 1) → 小数部分为 0,停止 → 顺序取数得 01
11.
对于十六进制,以%X读取或打印,表示是大写字母A-F表示10-15,而%x表示小写字母a-f表示10-15
12.
随机生成不重复的数:
int exsit(int* arr,int x){ for (int i = 0; i < 10; i++) { if(arr[i]==x) return 1; } return 0; } void main(){ srand(time(NULL)); // 需要引入time.h头文件,获取当前系统时间,用于初始化随机数种子 int i=0; int arr[10]={0}; while (i<10) { int temp=rand()%100+1; // rand()生成随机数 if(!exsit(arr,temp)){ arr[i++]=temp; } } for (int j = 0; j < 10; j++) { printf("%d ",arr[j]); } }13.
复习一下PTA天梯赛第50题,字母(纯小写或纯大写)可以视为数字0-25,对于
字符串aaa可以视为各位数字为0,即000。如果给了一个总数,可以不断除以进制来获取各位数字(相当于字符)
14.
scanf不会跳过,(逗号)!,当输入是逗号时万分注意!
15.
大数加法可以直接反转就输出、不用处理前导零,本质是加法的进位逻辑天然不会产生 “无效的前导零”,而减法的借位逻辑会产生(n1-n2之前,需要先n1-=borrow)
大数加法和减法逻辑类似,可共用一套流程逻辑
除法学内置不断相减,试商法的算法思想,防止填空题!
大数乘法需要注意res[i+j]+=(A[i]-'0'])*(B[j]-'0'),A的个位*B的十位和A的十位*B的个位都是结果的同一位有影响,结果需要累加起来
16.
使用memset快速初始化数组:
void *memset(void *str, int c, size_t n)
参数
- str-- 指向要填充的内存区域的指针。
- c-- 要设置的值,通常是一个无符号字符。
- n-- 要被设置为该值的字节数。
当你申请了一块内存或定义了一个大数组时,可以用它快速将所有位设为 0。
- 示例:
memset(arr, 0, sizeof(arr));
17.
计算约数个数,用质因数分解法
把数拆成质数的次方形式,每个次方数 +1,全部乘起来,就是约数总个数
先质因数分解:90 =2¹ × 3² × 5¹
每个指数 +1:1+1 = 22+1 = 31+1 = 2
相乘:2 × 3 × 2 =12
所以90 有 12 个约数
整体思路是因式分解(先找约数2),然后从3开始找奇质数,用数组存不同质因数的出现次数(指数)
#include <stdio.h> #include <stdlib.h> void main(){ int n; scanf("%d",&n); long long mul=1; for(int i=0;i<n;i++){ int temp; scanf("%d",&temp); mul*=temp; } // 分解成质因数 int arr[10000]={0}; 善用开大数组,省去动态分配 if(mul==1){ printf("1\n"); return; } int len=0; int a=0; while(mul%2 == 0){ a=1; arr[len]++; mul=mul/2; } if(a) len++; int m=mul; for(int i=3;i<=m;i=i+2){ int flag=0; while(mul%i ==0){ flag=1; arr[len]++; mul=mul/i; } if(flag){ len++; } } int res=1; for(int i=0;i<len;i++){ res*=arr[i]+1; } printf("%d\n",res); }18.
求多个数的最大公约数和最小公倍数,核心是两两相求;
比如求:2、3、4 的最大公约数
- 先求2 和 3 的 GCD→ 1
- 再用结果1 和 4 求 GCD→ 1
所以:gcd(2,3,4) = 1
求:2、3、4 的最小公倍数
先求 LCM (2,3)LCM = 2×3 ÷ gcd (2,3) = 6 ÷ 1 = 6
再求 LCM (6,4)gcd (6,4)=2LCM = 6×4 ÷ 2 = 24÷2 =12
所以:LCM(2,3,4) = 12
19.
- 阶乘末尾尾随零的数量 =
n!中 5 的总个数(因为 2 的数量足够多); - 统计 5 的总个数需用
n//5 + n//25 + n//125 + ...(直到除数 > n),而非仅算能被 5 整除的数;
#include <stdio.h> int count_trailing_zeros(int n) { int zero_count = 0; 下面求n!中含多少个5 // 循环计算5的各次幂的贡献,直到除数超过n while (n >= 5) { n = n / 5; // 等价于整数除法,依次算n//5、n//25、n//125... zero_count += n; // 累加每一轮的5因子数 } return zero_count; } int main() { int n; scanf("%d", &n); printf("%d\n", count_trailing_zeros(n)); return 0; }20.
向上取整就是取更大的数,正数取绝对值更大,负数取绝对值更小;
向下取整就是取更小的数
C语言默认正数除法是直接丢掉小数部分
round函数可以实现正、负的四舍五入,只看小数部分的绝对值决定是舍去还是进1,不看符号