(仅个人观点)
最近了解到一种新兴语言—— Julia(不要问我为什么取这个名字,我也不知道)。这种语言主要用于科学计算和数学领域,也可用于程序开发。
下面是该语言的几个特点:
下面的代码所执行的操作是相同的。
| C++ 代码 | Julia 代码 |
|---|---|
int a = 2 * b; | a = 2b |
int a = (3 + 1) * b; | a = (3 + 1)b |
int a = (3 + b) * c + 5 / d; | a = (3 + b)c + 5 ÷ d |
int a = (a + c * d) * arr[2]; | a = (a + c * d)arr[3](Julia 语言下标从 1 开始) |
int a = b * b * b; | a = b ^ 3(Julia 中 ^ 表示幂运算) |
int a = ~(b & c);(与非运算) | a = b ⊼ c(Julia 中 ⊼ 表示与非运算) |
int a = b ^ c;(异或运算) | a = b ⊻ c |
bool a = b <= c; | a = b ≤ c |
bool a = b != c; | a = b ≠ c |
bool a = (b <= c) && (c <= d); | a = b ≤ c ≤ d |
bool a = find(vec.begin(), vec.end(), b) != vec.end();(查找值 b 在不在 vec 中) | a = b ∈ vec(如果是查找是否不在其中,使用 ∉ 运算符) |
在 C++ 中,声明只有一个返回语句的函数要这么写:
int myfunc(int a, int b, int c) {
return (a + b) * c;
}
但在 Julia 中,其就像数学函数一样:
pow(a, b, c) = (a + b)c
Julia 已经定义了很多特殊的 Unicode 数学符号作为运算符,但实际上,Julia 除了能像 C++ 一样重载运算符,还能自定义运算符。例如,如果自定义中缀运算符:
⊕(a, b) = (a - 1) * (b + 1)
就可以这样使用:
a = 2 ⊕ 4
# a 的值为 (2 - 1) * (4 + 1) = 1 * 5 = 5
如果想对 C++ 的一个数组 a 中的所有元素加上 2,并存储到另一个数组 b 中,得这么写:
// 假设数组长度为 10
for (int i = 0; i < 10; i++) {
b[i] = a[i] + 2;
}
但 Julia 不需要写循环:
b = a .+ 2
加上点号,就是批量操作。
在 C++ 中,如果我们想要写三重嵌套循环,并且最内层退出时必须退出三层。我们得这么写:
for (int i = 1; i <= x; i++) {
bool flag = false;
for (int j = 1; j <= y; j++) {
for (int k = 1; k <= z; k++) {
if (i + j + k == n) {
flag = true;
break;
}
}
if (flag) {
break;
}
}
if (flag) {
break;
}
}
或者使用不推荐的 goto:
for (int i = 1; i <= x; i++) {
for (int j = 1; j <= y; j++) {
for (int k = 1; k <= z; k++) {
if (i + j + k == n) {
goto out_loop;
}
}
}
}
out_loop:
void; // 占位符,因为标签后必须是一条语句
但是,在 Julia 中,可以直接这么写:
for i = 1:x, j = 1:y, k = 1:z # 三重循环
if i + j + k == n
break # 将直接跳出所有循环
end
end
这是用 Julia 写的线段树,其中加上了类型标注。
struct SegmentTree
sum::Vector{Int}
add_tag::Vector{Int}
SegmentTree(n::Int) = new(zeros(4n), zeros(4n)) # 构造函数
end
function build(st::SegmentTree, k::Int, l::Int, r::Int, init::Vector{Int})::Nothing
if l == r
st.sum[k] = init[l]
return
end
mid::Int = (l + r) ÷ 2 # 整除,/ 是浮点除法
build(st, 2k, l, mid, init)
build(st, 2k + 1, mid + 1, r, init)
end
function modify(st::SegmentTree, k::Int, l::Int, r::Int, x::Int, y::Int, v::Int)::Nothing
if x ≤ l && r ≤ y
st.add_tag[k] += v
return
end
st.sum[k] += (min(r, y) - max(l, x) + 1)v;
mid::Int = (l + r) ÷ 2
if x ≤ mid
modify(st, 2k, l, mid, x, y, v)
end
if mid < y
modify(st, 2k + 1, mid + 1, r, x, y, v)
end
end
function query(st::SegmentTree, k::Int, l::Int, r::Int, x::Int, y::Int)::Int
if x ≤ l && r ≤ y
return st.sum[k] + (r - l + 1)st.add_tag[k]
end
mid::Int = (l + r) ÷ 2
res::Int = (min(r, y) - max(l, x) + 1)st.add_tag[k]
if x ≤ mid
res += query(st, 2k, l, mid, x, y)
end
if mid < y
res += query(st, 2k + 1, mid + 1, r, x, y)
end
return res
end
function main()::Nothing # 主函数,实际上并不必要,Julia 像 Python 一样可以直接写代码
n::Int, m::Int = parse.(Int, split(readline())) # 分解读取。注意点号表示批量操作
# println("n = $n, m = $m")
init::Vector{Int} = parse.(Int, split(readline()))
st::SegmentTree = SegmentTree(n)
build(st, 1, 1, n, init)
for i::Int = 1:m # Julia 的循环
input::Vector{Int} = parse.(Int, split(readline()))
opt::Int, x::Int, y::Int = input[1:3]
if opt == 1
v::Int = input[4]
modify(st, 1, 1, n, x, y, v)
elseif opt == 2
println(query(st, 1, 1, n, x, y))
end
end
end
main() # 由于 Julia 是直接执行代码的,所以我们要手动执行封装号的主函数