@donghanyuan0609
2020-04-18T14:26:23.000000Z
字数 3377
阅读 387
2020年4月18日 19:00
for, while的括号后面手滑加了分号
while (scanf("%d%d%d%d", &n, &x, &y, &k) != EOF); // !!!{y = (y + n - x + k) % 7;switch (y) {// code here ......}}for (int i = 0 ; i < n; i++);{// code here}
i, j写混(内层外层循环都用了同一个i,或者是内层循环一会儿写成i一会儿写成j)
for (i = 0; i < m; i++){// ......for (i = 1; i < m; i++) // for j{}}
数组那点事(全局!别正好开n个!)
数据范围的坑!(K题long long记住了吗)
#include <stdio.h>typedef long long ll; // 这样比较方便
再认识一下这位"罪魁祸首" -
\rwindows中,换行符是CR+LF(
"\r\n"), 在windows系统中体现不出来用
getchar逐个字符读取,只能读到一个'\n',识别不到'\r'。在linux系统(OJ评测机)中,默认的换行符是
"\n",'\r'会被当做一个普通的字符(分隔符)。会占一个字符长度!
Hello world
H e l l o SPACE w o r l d \nH e l l o SPACE w o r l d \r \n
用gets或者fgets有影响,用scanf("%s", s)无影响。
在windows系统中(本地调试)察觉不到,但提交到OJ上会有影响。
int a = 1, *p = &a; // 指针的定义int b = 2;p = &b;*p = 3; // b = 3;// 指针和数组名char str[1005], *ps;// 数组名就是首地址str == &str[0]ps = str;printf("%s", ps);puts(ps);char s[105] = "hello", *p = "world";s[0] = 'b'; p = "cprogramming";
为什么要交换指针
81 10 2 8 7 11 3 6
int n, x, i;int max = 0;scanf("%d", &n);for (i = 0; i < n; i++) {scanf("%d", &x);if (x > max) max = x;}
char buf[10005], longest[10005];int max_len = 0, len;while (gets(buf) != NULL) {len = strlen(buf);if (len > max_len) {strcpy(longest, buf); // Time costmax_len = len;}}
两个数组在任何时刻:其中一个数组负责接受新的输入,另一个数组负责存储最长串。
两个数组没有本质的区别。
省去strcpy传递的过程。
任何时刻,总有一个指针指向存储最长串的数组,另一个指针指向的数组用于接受新的输入。
tmp = in_line;in_line = longest;longest = tmp;t = x; x = y; y = t;
// 遍历一个字符串// 数组方式// l = strlen(s);for (i = 0; s[i] ; i++) {putchar(s[i]);}// 指针方式char *p = s;p[0] = 's'; *(s + 1) = '1';for (p = s; *p; p++) {putchar(*p);}// 区间的反转(指针)
排除重复的计算
第一遍算,循环4遍。
第二遍算,循环10遍
算,循环遍。
算,循环遍。
算,循环遍。
算,循环遍。
。。。。。。
算,循环遍。
#define MOD 1000003int fact[1000005] = {1}, sum[1000005] = {1};int main(){// 先预处理再输入for (i = 1; i <= 1000000; i++){fact[i] = (1LL * fact[i - 1] * i) % MOD;sum[i] = (sum[i - 1] + fact[i]) % MOD;}scanf("%d", &q);while (q--){scanf("%d", &n);printf("%d\n", sum[n]);}}
易错点:不要使用递归(SIGSEGV)
Key: 红组用排序,黑组用散列(数组计数)
红组个数少但是数据元素比较分散,
黑组数据个数多,但是数值相对集中
// 红组:排序(所有相同的值连在一起)// 统计最长的连续相等片段的长度// 假设红组已经排完序了int cnt = 0, max_red = 0, ans_red = 0;// cnt: 以当前元素结尾的最长相等连续段的长度for (i = 1; i <= m; i++){if (i > 1 && red[i] == red[i - 1])cnt++;elsecnt = 1;if (cnt > max_red)max_red = cnt, ans_red = red[i];}// 黑组for (i = 1; i <= n; i++){scanf("%d", &x);cnt_black[x]++;if (cnt_black[x] > max) {}else if (cnt_black[x] == max) {}}for (i = 1; i <= 1000; i++) {if (cnt_black[x] >= max) // 更新最大值}
小结:
- 时间的力量:排序
坑多!
Hint多
\r:我没存在感吗?
gets(s);// 去掉末尾的第一个分号int l = strlen(s);while (s[--l] != ';');s[l] = 0;
只需要将替换的位置输出即可,不需要真正在原处替换
strstr函数:若匹配:则返回匹配位置(首字符的地址);若不匹配,则返回NULL。
匹配到了,直接输出要换成的新串;
如果没匹配:原样输出
char *slow = s, *fast = s;while ((fast = strstr(slow, a)) != NULL) {while (slow < fast) putchar(*(slow++)); // 当前位置到匹配点之间printf("%s", b); // 输出替换为的串bslow += len_a; // 直接跳过要匹配的串a}while (*slow) putchar(*(slow++));putchar(';');
单词开头:自己是字母,并且要么在句首要么上一个不是字母
单词结尾:自己是字母,要么下一个字符不是字母(字符串结尾是'\0')
用指针或下标变量标记单词的开头(或者结尾)
区间反转:
void rev(char *s, char *t){char tmp;for (; s < t; s++, t--) // s, t始终指向区间的对称位置{tmp = *s;*s = *t;*t = tmp;}}
先转外圈,再将边界向里各退缩一格。
可以用递归来做,也可以用循环来做。
输入
又是
\r惹的祸
char a[1005][1005];for (i = 0; i < n; i++){for (j = 0; j < n; j++)a[i][j] = getchar();//getchar(); // \n or \r\nwhile (getchar() != '\n');}
vis, cnt, ... 都是他置换的分解,Taylor Swift
for (j = i; j != n; j = next[j])vis[j] = 1;
只需要知道当前的状态和上一个状态的关系,不需要知道更早的状态
由s[i - 1]推s[i]
把一个大问题分解成类似的小问题
求最大公约数,求阶乘,汉诺塔
层次比较深但是不分叉的递归,能否直接循环搞定?
可以迭代的问题(这个勇者很菜,斐波那契,求阶乘,公约数)
求组合数
w位数当前状态怎么由之前已有的(数据规模比较小的)状态得到