在使用 C# 语言解 ACM 题的时候,如果能够有一个 ReadInt32 方法直接从标准输入读取整数比较方便的。下面就是一个 I/O 助手类 IOHelper:
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
namespace
Skyiv
{
using
System;
using
System.IO;
using
System.Text;
sealed
class
IOHelper : IDisposable
{
static
readonly
Encoding Encoding = Encoding.ASCII;
// or UTF8 ?
static
readonly
byte
[] EOLS = Encoding.GetBytes(Environment.NewLine);
static
readonly
byte
[] BLANKS = { 9, 10, 13, 32 };
// tab,lf,cr,space
static
readonly
byte
EOF = 0;
// assume '\0' not in input file
byte
[] buf =
new
byte
[32];
// for Write(int n)
byte
[] buffer =
new
byte
[64 * 1024];
int
current = 0;
int
count = 0;
BinaryReader reader;
BinaryWriter writer;
public
IOHelper()
:
this
(Console.OpenStandardInput(), Console.OpenStandardOutput())
{}
public
IOHelper(Stream reader, Stream writer)
{
this
.reader =
new
BinaryReader(reader);
this
.writer =
new
BinaryWriter(writer);
}
byte
ReadByte()
{
if
(current >= count)
{
count = reader.Read(buffer, current = 0, buffer.Length);
if
(count == 0)
return
EOF;
}
return
buffer[current++];
}
public
static
byte
[] GetBytes(
string
str)
{
return
Encoding.GetBytes(str);
}
public
int
ReadInt32()
{
var
n = 0;
var
ok =
false
;
for
(
byte
b; (b = ReadByte()) != EOF; )
{
if
(Array.IndexOf(BLANKS, b) >= 0)
if
(ok)
break
;
else
continue
;
n = n * 10 + (b -
'0'
);
ok =
true
;
}
return
n;
}
public
int
ReadLine(
byte
[] buffer)
{
var
n = 0;
while
(n < buffer.Length)
{
var
b = ReadByte();
if
(b == EOLS[0])
{
if
(EOLS.Length == 2 && ReadByte() != EOLS[1])
throw
new
InvalidDataException(
"Invalid EOL"
);
break
;
}
buffer[n++] = b;
}
return
n;
}
public
void
Write(
int
n)
{
if
(n == 0) { writer.Write((
byte
)
'0'
);
return
; }
var
i = buf.Length;
for
(; n > 0; n /= 10) buf[--i] = (
byte
)((n % 10) +
'0'
);
Write(buf, i, buf.Length - i);
}
public
void
Write(
byte
[] buffer,
int
index,
int
count)
{
writer.Write(buffer, index, count);
}
public
void
Write(
string
str)
{
var
buffer = Encoding.GetBytes(str);
writer.Write(buffer, 0, buffer.Length);
}
public
void
WriteSpace()
{
writer.Write(BLANKS, 3, 1);
}
public
void
WriteLine()
{
writer.Write(EOLS, 0, EOLS.Length);
}
public
void
Dispose()
{
if
(reader !=
null
) reader.Close();
if
(writer !=
null
) writer.Close();
}
}
}
|
此外,IOHelper 类还提供以下方法用于处理字符串:
- public int ReadLine(byte[] buffer)
- public void Write(byte[] buffer, int index, int count)
类似于 C/C++ 语言,这两个方法仅仅把字符串当作字节数组处理,使用 ASCII 码。而不是象 C# 语言中字符串是使用 Unicode 进行编码。
下面是一个使用示例,题目来源请参见“I-Keyboard”这篇随笔。
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
namespace
Skyiv.Ben.Acm
{
using
System;
sealed
class
Ikeyb
{
const
int
MAX = 90;
static
int
[,] cost =
new
int
[MAX + 1, MAX + 1];
static
int
[,] price =
new
int
[MAX + 1, MAX + 1];
static
int
[,] index =
new
int
[MAX + 1, MAX + 1];
static
int
[] F =
new
int
[MAX];
static
byte
[] keys =
new
byte
[MAX];
static
byte
[] letters =
new
byte
[MAX];
static
byte
[] message1 = IOHelper.GetBytes(
"Keypad #"
);
static
byte
[] message2 = IOHelper.GetBytes(
": "
);
static
IOHelper helper;
static
void
Main()
{
using
(helper =
new
IOHelper())
{
var
runner =
new
Ikeyb();
var
T = helper.ReadInt32();
for
(
var
n = 1; n <= T; n++) runner.Run(n);
}
}
void
Run(
int
n)
{
var
K = helper.ReadInt32();
var
L = helper.ReadInt32();
helper.ReadLine(keys);
helper.ReadLine(letters);
for
(
var
i = 0; i < L; i++) F[i] = helper.ReadInt32();
Initialize(K, L);
Compute(K, L);
helper.Write(message1, 0, message1.Length);
helper.Write(n);
helper.Write(message2, 0, 1);
helper.WriteLine();
Output(K, L);
helper.WriteLine();
}
void
Initialize(
int
K,
int
L)
{
for
(
var
i = 0; i <= K; i++)
for
(
var
j = 1; j <= L; j++)
price[i, j] =
int
.MaxValue / 2;
for
(
var
i = 1; i <= L; i++)
for
(
var
j = i; j <= L; j++)
cost[i, j] = cost[i, j - 1] + (j - i + 1) * F[j - 1];
}
void
Compute(
int
K,
int
L)
{
for
(
var
i = 1; i <= K; i++)
for
(
var
j = i; j <= L; j++)
for
(
var
n = 1; n <= j - i + 1; n++)
{
var
sum = price[i - 1, j - n] + cost[j - n + 1, j];
if
(sum <= price[i, j])
{
price[i, j] = sum;
index[i, j] = n;
}
}
}
void
Output(
int
K,
int
L)
{
if
(K == 0)
return
;
var
n = index[K--, L];
Output(K, L - n);
helper.Write(keys, K, 1);
helper.Write(message2, 0, message2.Length);
helper.Write(letters, L - n, n);
helper.WriteLine();
}
}
}
|
如果给出以下输入:
1 2 5 *# ABCDE 1024 32768 2147483647 987 654321
上述程序将产生以下输出:
Keypad #1: *: ABCD #: E
注意上述输出其实是有问题的,正确的输出应该分为 AB 和 CDE 两组。但是程序本身是没有问题的,而是输入数据有问题。因为原来的题目中限定各个字母出现的频率不能超过 100000。