基本上就是按照大白学习的,基本上都是计数方法的运用。
这是的大体的对组合数学的学习导图。
基本上就是按照大白学习的,基本上都是计数方法的运用。
这是的大体的对组合数学的学习导图。
#include <cstdio> #include <cmath> #include <iostream> #include <algorithm> using namespace std; struct Ant { int id; int p; int d; bool operator < (const Ant& a) const { return p < a.p; } }; const int MAXN = 10010; const char dirName[][10] = {"L", "Turning", "R"}; Ant before[MAXN], after[MAXN]; int order[MAXN]; int main(int argc, const char *argv[]) { freopen("input", "r", stdin); int t; int L, T, n; int p, d; char c; scanf("%d", &t); for(int kase = 1; kase <= t; kase++) { printf("Case #%d:\n", kase); scanf("%d%d%d", &L, &T, &n); for(int i = ; i < n; i++) { scanf("%d %c", &p, &c); d = c == 'L' ? -1 : 1; before[i] = (Ant) {i, p, d}; after[i] = (Ant) {, p+T*d, d}; } sort(before, before+n); for(int i = ;i < n;i ++) order[before[i].id] = i; sort(after, after+n); for(int i = ; i < n; i++) if(after[i].p == after[i+1].p) after[i].d = after[i+1].d = ; for(int i = ; i <n; i++) { int a = order[i]; if(after[a].p < || after[a].p > L) puts("Fell off"); else printf("%d %s\n", after[a].p, dirName[after[a].d+1]); } printf("\n"); } return ; } #include <cstdio> #include <cmath> #include <iostream> #include <algorithm> using namespace std; struct Ant { int id; int p; int d; bool operator < (const Ant& a) const { return p < a.p; } }; const int MAXN = 10010; const char dirName[][10] = {"L", "Turning", "R"}; Ant before[MAXN], after[MAXN]; int order[MAXN]; int main(int argc, const char *argv[]) { freopen("input", "r", stdin); int t; int L, T, n; int p, d; char c; scanf("%d", &t); for(int kase = 1; kase <= t; kase++) { printf("Case #%d:\n", kase); scanf("%d%d%d", &L, &T, &n); for(int i = ; i < n; i++) { scanf("%d %c", &p, &c); d = c == 'L' ? -1 : 1; before[i] = (Ant) {i, p, d}; after[i] = (Ant) {, p+T*d, d}; } sort(before, before+n); for(int i = ;i < n;i ++) order[before[i].id] = i; sort(after, after+n); for(int i = ; i < n; i++) if(after[i].p == after[i+1].p) after[i].d = after[i+1].d = ; for(int i = ; i <n; i++) { int a = order[i]; if(after[a].p < || after[a].p > L) puts("Fell off"); else printf("%d %s\n", after[a].p, dirName[after[a].d+1]); } printf("\n"); } return ; }
排序,贪心
#include <stdio.h> #include <algorithm> using namespace std; int main() { // freopen("input", "r", stdin); const int MAXN = 20010; int dra[MAXN]; int sol[MAXN]; int m, n; while(scanf("%d%d", &n, &m)) { if(n == m && n == ) break; for(int i = ; i < n; i++) scanf("%d", &dra[i]); for(int i = ; i < m; i++) scanf("%d", &sol[i]); sort(dra, dra+n); sort(sol, sol+m); int i, j, cost; i = j = cost = ; for(;;) { if(i == n || j == m) break; if(dra[i] > sol[j]) j++; else { cost += sol[j]; i++; j++; } } if(i == n) printf("%d\n", cost); else puts("Loowater is doomed!"); } return ; }
这个题目很有价值。
一方面通过数学推导得出结论。
编号为i的人初始有$A_i$枚金币。对于1号,给了4号$x_1$枚金币,自己还有$A_1-x_1$枚。然后从2号拿走$x_2$枚金币,现在有$A_1-x_1+x_2$枚金币,另外,设平均金币值为$A_1-x_1+x_2=M$。
由此可类推得到
$A_n-x_n+x_1 \Rightarrow x_n=M-A_n+x_1=x_n-C_n$
我们可以得到类推公式
$$C_i = C_{i-1} + A_i – M $$
证明:
$$x_2 = x_1 – C_1$$
$$x_3 = M-A_2+x_2 =2M-A_1-A_2+x_1=x_1-C_2$$\
以此类推。
可以求得,需要求的结果为:
$$|x_1|+|x_1-C_1|+|x_1-C_2|….|x_1-C_n-1|$$
即求这个式子值最小,即求$C_1, C_2, …C_n$的中位数。
#include <stdio.h> #include <algorithm> #include <math.h> #define lln long long using namespace std; const int MAXN = 1000000 + 10; lln gold[MAXN], C[MAXN]; int main() { // freopen("input", "r", stdin); lln n, sum, per, cnt; while(~scanf("%lld", &n)) { sum = ; for(int i = ; i < n; i++) { scanf("%lld", &gold[i]); sum += gold[i]; } per = sum / n; C[] = ; for(int i = ; i < n; i++) C[i] = C[i-1] + gold[i] - per; sort(C, C+n); cnt = ; lln x1 = C[n/2]; for(int i = ; i < n; i++) cnt += abs(x1 - C[i]); printf("%lld\n", cnt); } return ; }
这个题目也是比较有水平
使用了按比例缩小的技巧。其中,按逆时针编号,固定一个点作为原点,建立新坐标。原来的位置呈现在新坐标的位置为$pos = i/n*(n+m)$,如此,求移动距离则是$fabs(pos – floor(pos+0.5))/(n+m)$
[阅读全文]本文出自svtter.github.io
printf("%d %o %x\n", a);
把整数按照十进制,八进制和十六进制输出.
$2^32-n$补码表示法.
使用Ctrl+D
时, getchar()读到的是-1
#include <stdio.h> #include <string.h> int main(int argc, const char *argv[]) { char c = getchar(); printf("%d%c\n", c, c); return ; }
假设一个年份为1993/12/12
, 那么如何简单获取年月日?
使用sscanf函数.
#include <stdio.h> #include <string.h> int main(int argc, const char *argv[]) { int year, month, day; char s[] = "1993/12/12"; sscanf(s, "%d/%d/%d", &year, &month, &day); printf("%d/%d/%d\n", year, month, day); return ; }
可以使用fgets(s, MAXN, stdin)
来获取简单的输入. 一次读入一行,包括空格,遇到\n结束读入
虽然是很水的题目,但是还是收获了不少。
#include <stdio.h> #include <math.h> int main() { int a, b, c; while(~scanf("%d %d %d", &a, &b, &c)) { printf("%.*lf", c, a/(double)b); } return ; }
// 整数位数 int cal(int a) { if(a == 0) return 0; return (int) log10( (double) a)+1; }
#include <stdio.h> #include <string.h> #define bool int //C语言没有bool bool light[1010]; //C也没有引用 void trans(bool *a) { if(*a) *a = ; else *a = 1; } int main() { int i, j; int n, k; while(~scanf("%d %d", &n, &k)) { memset(light, , sizeof(light)); for(i = 1; i <= k; i++) { j = i; while(j <= n) { trans(&light[j]); j += i; } } for(i = 1; i <= n; i++) { if(light[i]) printf("%d ", i); } printf("\n"); } return ; }
#include <stdio.h> #include <string.h> #define bool int //C语言没有bool bool light[1010]; //C也没有引用 void trans(bool *a) { if(*a) *a = ; else *a = 1; } int main() { int i, j; int n, k; while(~scanf("%d %d", &n, &k)) { memset(light, , sizeof(light)); for(i = 1; i <= k; i++) { j = i; while(j <= n) { trans(&light[j]); j += i; } } for(i = 1; i <= n; i++) { if(light[i]) printf("%d ", i); } printf("\n"); } return ; }
#include <stdio.h> #include <math.h> double calharmony(int a) { double sum = ; int i; for(i = 1; i <= a; i++) { sum += 1/(double)i; } return sum; } int main() { int a; while(~scanf("%d", &a)) { printf("%.3lf\n", calharmony(a)); } return ; }
题目都很水(不能再水了),但是也算是有所收获。学习了一部分C。
觉得自己的一些ACMer的基本素养不够,重新翻看。
pi = 4.0 * atan(1.0)
math.h
中的M_PI
并不是ANSI C标准。验证可以使用gcc -ansi
之前阅读了scanf
函数的相关部分(百科),但是依然没有很好的掌握。
现在依然没有= =。
有时间需要重新学习一下。
floor(m + 0.5) == m
通过+0.5来判断m的整数值。
floor/ceil
是数学库里提供的函数,默认gcc不会自动链接math库, 方法是(-l + 库)
gcc -Wall myround.c -lm -o myround
clock()
计时time.h
printf("Time used = %.2lf\n", (double)clock() / CLOCKS_PER_SEC);
会从程序开始的时候计时(不管输入输出),所以最佳方法是echo 数据 | ./a.out
多次使用clock()
来计时的吧。。。
int main() { #ifdef LOCAL freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif }
添加编译选项:-DLOCAL
, 使得中间部分生效.
fopen在linux不支持,所以不写了。
利用排列找规律。
首先利用next_permutation
函数进行求排列
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f int a[30]; int cal(int n) { int sum = ; int i; for (i = 1; i <= n; i++) { /* code */ sum = abs(sum - a[i]); } return sum; } void parray(int a[], int len) { int i; for (i = 1; i <= len; i++) { cout << a[i] << " "; } cout << endl; } void cp(int a[], int b[], int n) { int i; for (i = ; i <= n; i++) { a[i] = b[i]; } } int main(int argc, const char *argv[]) { int i; for (i = 1; i <= 30; i++) { a[i] = i; } int n; int maxa[30], mina[30]; while (~scanf("%d", &n)) { int max = -INF; int min = INF; if (n == 1) { cout << "1 1" << endl; cout << "1" << endl << "1" << endl; continue; } while (next_permutation(a+1, a+n+1)) { /* code */ int temp = cal(n); if (temp >= max) { max = temp; cp(maxa, a, n); } if (temp <= min) { min = temp; cp(mina, a, n); } } cout << min << " " << max << endl; for (i = 1; i <= n; i++) { cout << mina[i] << " "; } cout << endl; for (i = 1; i <= n; i++) { cout << maxa[i] << " "; } cout << endl; } return ; }
代码如上。
可以观察出规律,然后即可AC。
详细代码下次再写= =
#include <stdio.h> #include <string.h> #include <cmath> using namespace std; int main() { int i, n; int max, min; while(~scanf("%d", &n)) { max = min = ; for(i = n; i >= 1; i--) min = abs(min - i); for(i = n-1; i >= 1; i--) max = abs(max - i); max = abs(max - n); printf("%d %d\n", min, max); for(i = n; i >1 ; i--) printf("%d ", i); puts("1"); for(i = n-1; i >= 1; i--) printf("%d ", i); printf("%d\n", n); } return ; }
规律在代码中,很明确。
maker关于线性筛素数的论文。
做到欧拉线性筛法再做补充。(当时还写了个这?)
之前一直没有正视线性筛素数的问题。今天特意来写一个伪证明。如果当前的i不是素数,那么必然被之前的某个素数筛掉了。i × prime[j]。
一个合数必然可以写成几个素数的乘积,再或者就是p×i这种形式。如果能被i×p1筛掉之后则不需要i×p2继续筛了,i×p2可以写成p1×(i×p2)
例如12可以被6×2筛掉,之前4×3这种筛除就可以去掉。
不可能:i会一直到n,也就是整个范围都会包含在内。
memset(Prime, , sizeof(Prime)); memset(IsPrime, 1, sizeof(IsPrime)); for(i = 2 ; i <= n; i++) { if(IsPrime[i]) Prime[num++] = i; for(j = ; j < num && i * Prime[j] <= n; j++) { IsPrime[i * Prime[j]] = ; if(i % Prime[j] == ) break; } }
之前的错误在于筛素数的时候没有筛去2的倍数,所以出现后面的值错误。
这个题目的总结就是不作不会死- -好端端的暴力我非要用个bfs。
看见自己wrong了还以为是哈希的问题- =
最近都是用gcc+vim写代码,昨天突然写个代码算法出个逻辑bug,因为用了大量递归调用,DEB半天出不来也是醉了,于是
学习一下gdb——之前也是勉强使用过,但是明显感觉不爽阿。。所以这次好好学习,记录一下。
目前我能用到的几个命令:
<shell>: gdb <file>
(gdb): info break
(gdb): b[reak] + 行数/函数名 (可以用tab补全)
条件为真,则在断点处停止
– (gdb): b addr if condition
删除编号为1的断点, 如果不加参数,会删除所有断点
– (gdb): delete breakpoint 1
(gdb): disable breakpoint 1
(gdb): enable breakpoint 1
(gdb):r
(gdb):c
不进入单步执行
– (gdb):n
进入的单步
– (gdb):s[tep
以变量为var为例
(gdb):p var
(gdb):p
(gdb):p $[num]
(gdb):whatis p
(gdb):p add(a, b)
输出a后面的十个元素
[阅读全文]