本篇介绍了汇编指令中如何进行运算,包括加、减、乘、除

前置问题:

  1. 怎么做多字节的加减法?
  2. 为什么加减法指令不分有符号数和无符号数,而乘除法的有符号数和无符号数运算分别是不同的指令
  3. 如何确定指令执行的是字节操作还是字操作?
  4. 符号扩展指令再什么时候会用到,如何用?
  5. 取负指令NEG为什么执行的是取反加一?
Read more »

块状链表大概就长这样。

不难发现块状链表就是一个链表,每个节点指向一个数组。 我们把原来长度为 n 的数组分为 个节点,每个节点对应的数组大小为 。 所以我们这么定义结构体,代码见下。

1
2
3
4
5
6
7
8
9
struct node {
node* nxt;
int size;
char d[(sqn << 1) + 5];

node() { size = 0, nxt = NULL, memset(d, 0, sizeof(d)); }

void pb(char c) { d[size++] = c; }
};

块状链表应该至少支持:分裂、插入、查找。 什么是分裂?分裂就是分裂一个 node,变成两个小的 node,以保证每个 node 的大小都接近 (否则可能退化成普通数组)。当一个 node 的大小超过 时执行分裂操作。

Read more »

为了解决高斯模型的单峰性的问题,我们引入多个高斯模型的加权平均来拟合多峰数据: 引入隐变量 ,这个变量表示对应的样本 属于哪一个高斯分布,这个变量是一个离散的随机变量: 作为一个生成式模型,高斯混合模型通过隐变量 的分布来生成样本。

Read more »

在EM算法的介绍中使用到了不等式,笔者意识到自己对这些数学知识已经有些生疏了,因此这篇博客回顾一下不等式的知识。

Read more »

块状数组,即把一个数组分为几个块,块内信息整体保存,若查询时遇到两边不完整的块直接暴力查询。一般情况下,块的长度为 。详细分析可以阅读 2017 年国家集训队论文中徐明宽的《非常规大小分块算法初探》。

块状数组的建立

下面直接给出一种建立块状数组的代码。

1
2
3
4
5
6
7
8
9
10
num = sqrt(n);
for (int i = 1; i <= num; i++)
st[i] = n / num * (i - 1) + 1, ed[i] = n / num * i;
ed[num] = n;
for (int i = 1; i <= num; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
belong[j] = i;
}
size[i] = ed[i] - st[i] + 1;
}

其中 st[i]ed[i] 为块的起点和终点,size[i] 为块的大小。

保存与修改块内信息

例题:教主的魔法

两种操作:

  1. 区间 每个数都加上
  2. 查询区间 内大于等于 的数的个数。

我们要询问一个块内大于等于一个数的数的个数,所以需要一个 t 数组对块内排序,a 为原来的(未被排序的)数组。对于整块的修改,使用类似于标记永久化的方式,用 delta 数组记录现在块内整体加上的值。设 为查询和修改的操作次数总和,则时间复杂度

delta 数组记录每个块的整体赋值情况。

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
void Sort(int k) {
for (int i = st[k]; i <= ed[k]; i++) t[i] = a[i];
sort(t + st[k], t + ed[k] + 1);
}

void Modify(int l, int r, int c) {
int x = belong[l], y = belong[r];
if (x == y) // 区间在一个块内就直接修改
{
for (int i = l; i <= r; i++) a[i] += c;
Sort(x);
return;
}
for (int i = l; i <= ed[x]; i++) a[i] += c; // 直接修改起始段
for (int i = st[y]; i <= r; i++) a[i] += c; // 直接修改结束段
for (int i = x + 1; i < y; i++) delta[i] += c; // 中间的块整体打上标记
Sort(x);
Sort(y);
}

int Answer(int l, int r, int c) {
int ans = 0, x = belong[l], y = belong[r];
if (x == y) {
for (int i = l; i <= r; i++)
if (a[i] + delta[x] >= c) ans++;
return ans;
}
for (int i = l; i <= ed[x]; i++)
if (a[i] + delta[x] >= c) ans++;
for (int i = st[y]; i <= r; i++)
if (a[i] + delta[y] >= c) ans++;
for (int i = x + 1; i <= y - 1; i++)
ans +=
ed[i] - (lower_bound(t + st[i], t + ed[i] + 1, c - delta[i]) - t) + 1;
// 用 lower_bound 找出中间每一个整块中第一个大于等于 c 的数的位置
return ans;
}

练习

  1. 单点修改,区间查询
  2. 区间修改,区间查询
  3. 【模板】线段树 2
  4. 「Ynoi2019 模拟赛」Yuno loves sqrt technology III
  5. 「Violet」蒲公英
  6. 作诗
0%