CST数据结构(2020秋)PA1a
1-1 A*B Problem
心得
- 每个数组存一位的话速度太慢过不了,必须压位
- 10e5 是 10 * 10^5 所以是 10^6 …
- 我们把一个大整数分成几块存在数组里的时候,如果这个数头上有0的话,0就会被忽略了(不压位的话没有这个问题,因为0也就是1位)比如4位4位存,100046000303025会变成[3025, 30, 460, 100],直接输出会变成100460303025,明显不对,所以我们输出的时候要记得补全0
代码
1 |
|
Reference
1-3 Filename
心得
编辑距离,移动窗口节省空间
字符串的读入:一开始以为是
getline
的问题,读不进来字符串,实际上是因为仅用scanf
读入3个整数后会留下一个换行符在 buffer 中。使用cin.ignore(100,'\n')
删除换行符(忽略 100 个字符,或者忽略1个'\n'
;忽略所有读入,直到总共忽略了 100 个字符,或者忽略了 1 个换行符)dp数组开到 $1001^2$ 会爆炸,改用滚动窗口,
dp[0][j]
表示 $ x_1x_2…x_{i-1}$ 到 $y_1 y_2 … y_j$ (前一步)所需要的操作,dp[1][j]
表示 $ x_1x_2…x_{i-1}$ 到 $y_1 y_2 … y_j$ (这一步)所需要的操作。几个实现细节在注释中已标出TLE
: 第一感觉想的是在每次计算 $i, s.t. x_1x_2…x_i$ 变成 $y$ 所需要的操作后(即计算完成dp[i][0...m]
后),扫一遍数组,如果所有值都大于k
的话,就停止查找。但是这样不会对数据规模有任何可观的缩减,因为如果说我们有长为 $10^5$ 的两个字符串,并且他们可以在k
操作内互相转换(极端情况两个相同的字符串),我们仍然需要进行 $O(mn) = 10^5 \times 10^5$ 次操作。根据习题课的解决方法,其实当两个数组间的长度差超过
k
时就绝对不可能从一个转换成另一个了。所以,对于每个 $x$ 的子串 $x_1x_2…x_i$,我们只需要看 $y_{i-k} y_{i-k+1} … y_{i+k}$ 就可以了。当然还要注意 $i-k, i+k$别越界,所以实际上是看 $y_{min(1,i-k)} … y_{max(m,i+k)}$ 这个子序列这个改动会造成一些 WA,直觉一下子想到是有可能在最后退出循环时,我们因为
k
的限制压根就没扫到dp[n][m](= dp[1][m])
。实际上问题差不多,是因为dp[i][j] = min(dp[i-1][j], dp[i][(j-1)]) + 1;
这句话中dp[0][j]
我们一开始全初始化为0,对于dp[i][i+k]
这个位置,它的一种方案dp[i-1][i+k]
永远不会被上一步更新到,因为上一步只更新dp[i-1][(i-1)-k] ~ dp[i-1][(i-1)+k]
即dp[i-1][i+k]
恒等于0,即dp[i][i+k]
永远会采取dp[i-1][i+k]
这一方案。将dp[0][j]
初始化为 infinity 解决
代码
1 |
|
Reference
1.4 Risk
心得
Queap, 二分搜索
- 每次询问的时候,假设我们要看前
m
天,现在的 Queap 中存了 qsize 天,如果 qsize>m 的话,我们存了一些没必要看的天,那么我们就需要把这些没必要的天给推出去,所以看出来我们需要推出qsize-m
个没必要的天。然而我的实现在dequeap
和enqueap
时会实时更新qsize
所以实际上 Queap 只会弹出大概一半的元素,会造成很大的问题。所以我们必须先记录qsize-m
然后再更新 - 最后的T次询问是对已经有的数据,询问有多少在相应的区间内。我们这里可以使用排序后二分查找区间分界点的位置,而不是对于每个元素都看是在哪个区间内。这样可以大大缩短时间
代码
1 |
|