kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

数A到数B之间的统计

Problem 1896 神奇的魔法数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Accept: 98    Submit: 307
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

John定义了一种“神奇的魔法数”。 不含前导零且相邻两个数字之差至少为m的正整数被称为“神奇的魔法数”。特别的,对于任意的m,数字1..9都是“神奇的魔法数”。
John想知道,对于给定的m,在正整数a和b之间,包括a和b,总共有多少个“神奇的魔法数”?

Input

第一行一个数字T(1<=T<=100),表示测试数据组数。
接下来T行,每行代表一组测试数据,包括三个整数a,b,m。(1<=a<=b<=2,000,000,000, 0<=m<=9)

Output

对于每组测试数据,输出一行表示“神奇的魔法数”的个数。

Sample Input

7 1 10 2 1 20 3 1 100 0 10 20 4 20 30 5 1 10 9 11 100 9

Sample Output

9 15 100 5 3 9 1

Source福州大学第七届程序设计竞赛
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdio.h>

int n,m,d,dp[13][13],sum[13],dn[13],dm[13];


// DFS的时候这两个地方根据不同要求写。
int dfs(int da[], int dep, int all)
{
	int i,j,ret=0;
	if (dep == 0) return 1;
	for (i=0;i<da[dep];i++)
	{
		if (all > 0 || i > 0) {
			if (all == 0 || i-da[dep+1]>=d || i-da[dep+1]<=-d)
				ret += dp[dep][i];
		} else
			ret += sum[dep-1];
	}
	if (all == 0 || da[dep]-da[dep+1]>=d || da[dep]-da[dep+1]<=-d)
		ret += dfs(da, dep-1, all+da[dep]);
	return ret;
}

int main()
{
	int i,j,k,l,T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d %d %d", &m, &n, &d);
		for (i=0;i<13;i++)
			for (j=0;j<13;j++) dp[i][j] = 0;
		sum[0] = 0; sum[1] = 9;
		for (i=0;i<10;i++) dp[1][i] = 1;
		for (i=2;i<13;i++) {
			sum[i] = sum[i-1];
			for (j=0;j<10;j++) {
				for (k=0;k<10;k++)
					if (j-k>=d || j-k<=-d)
						dp[i][j] += dp[i-1][k];
				if (j > 0)
					sum[i] += dp[i][j];
			}
		}
//        for (i=0;i<=2;i++)
//            for (j=0;j<10;j++) printf("%d %d %d\n", i, j, dp[i][j]);
		i = 1; k = n;
		while (i < 13) {
			dn[i] = k % 10; k /= 10;
			i++;
		}
		i = 1; k = m-1;
		while (i < 13) {
			dm[i] = k % 10; k /= 10;
			i++;
		}
		n = dfs(dn, 11, 0);
		if (m == 1)
			m = 0;
		else
			m = dfs(dm, 11, 0);
		printf("%d\n", n-m);
	}
	return 0;
}

How many 0’s?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Time Limit: 1000MS
Memory Limit: 65536KTotal Submissions: 2997
Accepted: 1603

Description

A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ n. How many 0's will he write down?

Input

Input consists of a sequence of lines. Each line contains two unsigned 32-bit integers m and n, m ≤ n. The last line of input has the value of m negative and this line should not be processed.

Output

For each line of input print one line of output with one integer number giving the number of 0's written down by the monk.

Sample Input

10 11
100 200
0 500
1234567890 2345678901
0 4294967295
-1 -1

Sample Output

1
22
92
987654304
3825876150

Source

Waterloo Local Contest, 2006.5.27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.util.*;
import java.math.*;
import java.io.*;

public class Main {
	static long val,n,m,dp[][]=new long[13][13],a[]=new long[13],dn[]=new long[13], dm[]=new long[13], sum[]=new long[13];
	static long dfs(long dnm[], int dep, long all)
	{
		int i, j, k;
		long ret=0;
		if (dep == 0) return 0;
		for (i=0;i<dnm[dep];i++) {
			if (all > 0 || i > 0)
				ret += dp[dep][i]; // 需要计算前导0
			else
				ret += sum[dep-1]; // 不需要计算前导0
		}
		if (all > 0 && dnm[dep] == 0)
			ret += val % a[dep] + 1;
		ret += dfs(dnm, dep-1, all+dnm[dep]);
		return ret;
	}

	public static void main(String[] args) {
		int i,j,k,l;
		Scanner cin = new Scanner(System.in);
		a[1] = 10;
		for (i=2;i<13;i++) a[i] = a[i-1]*10;
		for (i=0;i<13;i++)
			for (j=0;j<13;j++) dp[i][j] = 0;
		dp[1][0] = 1;
		sum[0] = sum[1] = 0;
		for (i=2;i<13;i++) {
			sum[i] = sum[i-1];
			for (j=0;j<10;j++) {
				for (k=0;k<10;k++)
					dp[i][j] += dp[i-1][k];
				dp[i][j] += j==0 ? a[i-1] : 0;
				if (j > 0)
					sum[i] += dp[i][j];
			}
		}
		while (true) {
			m = cin.nextLong();
			n = cin.nextLong();
			if (m == -1 || n == -1) break;
			for (i=0;i<13;i++) dn[i] = dm[i] = 0;
			i = 1;
			val = n;
			while (val > 0) {
				dn[i] = val % 10;
				val /= 10;
				i++;
			}
			i = 1;
			val = m-1;
			while (val > 0) {
				dm[i] = val % 10;
				val /= 10;
				i++;
			}
			val = n;
			n = dfs(dn, 12, 0) + 1; // 0 还有一个0
			val = m-1;
			m = dfs(dm, 12, 0) + 1;
			if (val < 0) m = 0;
			System.out.println(n-m);
		}
	}
}

修改elf文件标记的源码路径debugedit,find-debuginfo

1
2
yum install rpm-build
sudo apt-get install rpm

/usr/lib/rpm/debugedit 用来改变源码查找路径。

1
2
3
4
5
6
7
8
9
10
11
$ /usr/lib/rpm/debugedit
Usage: debugedit [OPTION...]
  -b, --base-dir=STRING      base build directory of objects
  -d, --dest-dir=STRING      directory to rewrite base-dir into
  -l, --list-file=STRING     file where to put list of source and header file
	                     names
  -i, --build-id             recompute build ID note and print ID on stdout

Help options:
  -?, --help                 Show this help message
  --usage                    Display brief usage message

base-dir 长度要大等于 dest-dir
-i 输出build-id
-l 输出源编译文件位置,便于有需要的人打包

debugedit 会在.debug_info .debug_abbrev .debug_line .debug_str中将base_dir目录替换为dest_dir目录。
* 需要注意,如果base_dir是路径中除文件名的部分,则.debug_line中的The Directory Table的目录和.debug_info中的DW_AT_comp_dir(指向.debug_str的内容)不会替换。
如:
.debug_line中的Table中有一个目录为/root/Desktop,如果用 -b /root/Desktop则匹配不上这条。
* 因为:debugedit在匹配的时候在base_dir和dest_dir后面加了一个'/‘
其他部分能替换是因为他们存的是文件路径,不是文件夹路径


内核处理debuginfo的时候,只会替换DW_AT_comp_dir。因为DW_AT_name是一个相对地址


可以修改debugedit源码,base_dir、dest_dir后面不再默认添加'/‘,只是单纯的把base_dir替换成dest_dir

http://vault.centos.org/6.7/os/Source/SPackages/rpm-4.8.0-47.el6.src.rpm

http://vault.centos.org/5.11/updates/SRPMS/rpm-4.4.2.3-36.el5_11.src.rpm

删除tool/debugedit.c中的下面代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
    {
      p = malloc (strlen (base_dir) + 2);
      strcpy (p, base_dir);
      strcat (p, "/");
      free (base_dir);
      base_dir = p;
    }
  if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
    {
      p = malloc (strlen (dest_dir) + 2);
      strcpy (p, dest_dir);
      strcat (p, "/");
      free (dest_dir);
      dest_dir = p;
    }

debugedit -l在输出.debug_line的时候会去除base_dir、dest_dir前缀,由于他们不是以/结尾,所以输出的文件会以/开头,类似/net/ipv4/tcp_input.c,下一步按这个目录去copy文件时就copy不到。所以应该把开头的/去掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 064ac0a..bda05db 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -588,9 +588,9 @@ edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
          if (base_dir == NULL)
            p = s;
          else if (has_prefix (s, base_dir))
-           p = s + strlen (base_dir);
+           { p = s + strlen (base_dir); if (*p == '/') p++; }
          else if (has_prefix (s, dest_dir))
-           p = s + strlen (dest_dir);
+           { p = s + strlen (dest_dir); if (*p == '/') p++; }

          if (p)
            {

debugedit_el6

debugedit_el5


.debug_str段保存着所有全局变量的名字,以0x00作为每一个全局变量名的结束。
在其它段来调用名字时,是以其在.debug_str段的偏移量来实现的
gcc -g /root/Desktop/a.c -o /root/Desktop/a.out
用绝对路径编译,在.debug_str段中就会存下源文件路径,.debug_info的DW_TAG_compile_unit中的DW_AT_name对应.debug_str中的偏移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ objdump --dwarf=str a.out
....
  0x00000000 474e5520 4320342e 342e3720 32303132 GNU C 4.4.7 2012
  0x00000010 30333133 20285265 64204861 7420342e 0313 (Red Hat 4.
  0x00000020 342e372d 3429006c 6f6e6720 756e7369 4.7-4).long unsi
  0x00000030 676e6564 20696e74 002f726f 6f742f44 gned int./root/D
  0x00000040 65736b74 6f702f61 2e630075 6e736967 esktop/a.c.unsig
  0x00000050 6e656420 63686172 006d6169 6e006c6f ned char.main.lo
  0x00000060 6e672069 6e74002f 726f6f74 2f446573 ng int./root/Des
  0x00000070 6b746f70 0073686f 72742075 6e736967 ktop.short unsig
  0x00000080 6e656420 696e7400 73686f72 7420696e ned int.short in
  0x00000090 7400                                t.


$ objdump --dwarf=info a.out
.....
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
	< c>   DW_AT_producer    : (indirect string, offset: 0x0): GNU C 4.4.7 20120313 (Red Hat 4.4.7-4)
	<10>   DW_AT_language    : 1        (ANSI C)
	<11>   DW_AT_name        : (indirect string, offset: 0x39): /root/Desktop/a.c
	<15>   DW_AT_comp_dir    : (indirect string, offset: 0x67): /root/Desktop
	<19>   DW_AT_low_pc      : 0x4004c4
	<21>   DW_AT_high_pc     : 0x40051c
	<29>   DW_AT_stmt_list   : 0x0

1
$ /usr/lib/rpm/debugedit -b /root/Desktop -d /usr/src /root/Desktop/a.out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ objdump --dwarf=str a.out
...
  0x00000000 474e5520 4320342e 342e3720 32303132 GNU C 4.4.7 2012
  0x00000010 30333133 20285265 64204861 7420342e 0313 (Red Hat 4.
  0x00000020 342e372d 3429006c 6f6e6720 756e7369 4.7-4).long unsi
  0x00000030 676e6564 20696e74 002f7573 722f7372 gned int./usr/sr
  0x00000040 632f612e 63002f61 2e630075 6e736967 c/a.c./a.c.unsig
  0x00000050 6e656420 63686172 006d6169 6e006c6f ned char.main.lo
  0x00000060 6e672069 6e74002f 726f6f74 2f446573 ng int./root/Des
  0x00000070 6b746f70 0073686f 72742075 6e736967 ktop.short unsig
  0x00000080 6e656420 696e7400 73686f72 7420696e ned int.short in
  0x00000090 7400                                t.


$ objdump --dwarf=info a.out

...
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
	< c>   DW_AT_producer    : (indirect string, offset: 0x0): GNU C 4.4.7 20120313 (Red Hat 4.4.7-4)
	<10>   DW_AT_language    : 1        (ANSI C)
	<11>   DW_AT_name        : (indirect string, offset: 0x39): /usr/src/a.c
	<15>   DW_AT_comp_dir    : (indirect string, offset: 0x67): /root/Desktop
	<19>   DW_AT_low_pc      : 0x4004c4
	<21>   DW_AT_high_pc     : 0x40051c
	<29>   DW_AT_stmt_list   : 0x0

patch / git patch

1、diff

1
diff [options] from-file to-file  

简单的说,diff的功能就是用来比较两个文件的不同,然后记录下来,也就是所谓的diff补丁。语法格式:diff 【选项】 源文件(夹) 目的文件(夹),就是要给源文件(夹)打个补丁,使之变成目的文件(夹),术语也就是“升级”。下面介绍三个最为常用选项:

-r 是一个递归选项,设置了这个选项,diff会将两个不同版本源代码目录中的所有对应文件全部都进行一次比较,包括子目录文件。
-N 选项确保补丁文件将正确地处理已经创建或删除文件的情况。
-u 选项以统一格式创建补丁文件,这种格式比缺省格式更紧凑些

2、patch

1
2
3
patch [options] [originalfile [patchfile]]
but usually just
patch -pnum <patchfile>

简单的说,patch就是利用diff制作的补丁来实现源文件(夹)和目的文件(夹)的转换。这样说就意味着你可以有源文件(夹)――>目的文件(夹),也可以目的文件(夹)――>源文件(夹)。下面介绍几个最常用选项:

-p0 选项要从当前目录查找目的文件(夹)
-p1 选项要忽略掉第一层目录,从当前目录开始查找。


在这里以实例说明:

1
2
--- old/modules/pcitable       Mon Sep 27 11:03:56 1999
+++ new/modules/pcitable       Tue Dec 19 20:05:41 2000

如果使用参数-p0,那就表示从当前目录找一个叫做old的文件夹,在它下面寻找modules下的pcitable文件来执行patch操作。
如果使用参数-p1, 那就表示忽略第一层目录(即不管old),从当前目录寻找modules的文件夹,在它下面找pcitable。这样的前提是当前目 录必须为modules所在的目录。而diff补丁文件则可以在任意位置,只要指明了diff补丁文件的路径就可以了。当然,可以用相对路径,也可以用绝 对路径。不过我一般习惯用相对路径。

-E 选项说明如果发现了空文件,那么就删除它
-R 选项说明在补丁文件中的“新”文件和“旧”文件现在要调换过来了(实际上就是给新版本打补丁,让它变成老版本)

单个文件

1
2
3
diff –uN from-file to-file >to-file.patch
patch –p0 < to-file.patch
patch –RE –p0 < to-file.patch

目录

1
2
3
diff –uNr from-docu to-docu >to-docu.patch
patch –p1 < to-docu.patch
patch –R –p1 <to-docu.patch

git diff或者其他UNIX的diff命令生成patch的过程:

1
2
3
git diff  > patch
git diff  --cached > patch
git diff  branchname --cached > patch

这个时候当前目录下就会有一个patch文件,这是一个非git环境也可以使用的patch。对于这种patch,在git上使用要用git apply命令,如下:

1
git apply patch

由于这是一个类似UNIX下更新文件的操作,所以执行完上述操作之后,实际上是等于手动修改了文件,还要做一些git commit之类的操作。git apply 是一个事务性操作的命令,也就是说,要么所有补丁都打上去,要么全部放弃。可以先用git apply –check 查看补丁是否能够干净顺利地应用到当前分支中:git apply –check patch,如果执行完该命令之后没有任何输出,表示我们可以顺利采纳该补丁,接下来就是git上的提交了。

git format-patch生成的补丁,这是git专用的。常用命令如下:
1. 两个节点之间的提交: git format-patch 节点A 节点B
2. 单个节点: git format-patch -1 节点A (-n就表示要生成几个节点的提交)
3. 最近一次提交节点的patch :git format-patch HEAD^ 依次类推……

使用git format-patch命令生成的patch文件,包含了提交的附加信息:比如作者,时间等。再次基础上使用git am命令即可将此补丁应用到当前分支。注意应用完之后,你会发现当前分支多了一次提交记录,并且有完整的信息,而不是简单的修改文件。在对比一下,git diff 和git format-patch生成的patch一个重要不同之处,实际使用中会发现git diff一次只会生成一个patch文件,不管差别了多少个提交,都是一个;而git format-patch是根据提交的节点来的,一个节点一个patch。

git两种patch的比较:

兼容性:很明显,git diff生成的Patch兼容性强。如果你在修改的代码的官方版本库不是Git管理的版本库,那么你必须使用git diff生成的patch才能让你的代码被项目的维护人接受。

除错功能:对于git diff生成的patch,你可以用git apply –check 查看补丁是否能够干净顺利地应用到当前分支中;如果git format-patch 生成的补丁不能打到当前分支,git am会给出提示,并协助你完成打补丁工作,你也可以使用git am -3进行三方合并,详细的做法可以参考git手册或者《Progit》。从这一点上看,两者除错功能都很强。

版本库信息:由于git format-patch生成的补丁中含有这个补丁开发者的名字,因此在应用补丁时,这个名字会被记录进版本库,显然,这样做是恰当的。因此,目前使用Git的开源社区往往建议大家使用format-patch生成补丁。