玄学算法/精彩DS总结 Vaiz
21.Bit\ DP
(摘自zjBrave_shadow博客)
套路:
我们常常是要求
这个限制有些恶心,我们需要多一位来看是否被限制。
我们一般按位考虑,令
我们考虑把
dp[0][0] = 1;
for (int i = 0; i < Bit; ++ i)
for (int now = 0; now <= 1; ++ now)
for (int dig = 0; dig <= 9; ++ dig) if (now || (dig <= lim[i + 1]))
dp[i + 1][now || (dig < lim[i + 1])] += dp[i][now];//这里是<的原因是,
然后最后的答案就是
ans = dp[Bit][0] + dp[Bit][1];
不难发现这样写,每个位数的数都会被考虑到。因为我们枚举的时候允许了前缀
并且如果存在前缀
但是注意这样的话,全部为
22.Convex\ Optimization
凸优化是神仙难度的热点。详情可以见我的slide。
23.Constant\ Optimization
1.在开O2的时候,循环语句在只有一句话的时候非常快,我们可以将原本的多个语句通过预处理等形式让语句只有一句,可以大大提高循环效率。
2.你可以通过计算
unsigned long long
爆了多少次,再在最后减回来。
3.(与4一起摘自__debug博客)
std::string procStatus()
{
std::ifstream t("/proc/self/status");
return std::string(std::istreambuf_iterator<char>(t), std::istreambuf_iterator<char>());
}
//Beng哥改良版
string procStatus()
{
freopen("/proc/self/status","r",stdin);
string str,tmp;
while(getline(cin,tmp))str+=tmp+'\n';
fclose(stdin);
return str;
}
输出它,VmPeak是内存。
4.性能分析(卡常利器)
首先在编译时加入 -pg 选项, 然后运行该程序.
程序会跑得很慢, 同时目录下会产生一个 gmon.out.
等程序跑完了之后, 运行命令 gprof program_name > result.txt.
现在 result.txt 中包含了每个函数详尽的调用次数/时间/占总时间百分比等, 是不可多得的卡常利器.
最重要的一点, 比赛时也可以用.
5.
-fsanitize=address -fsanitize=undefined
后一个用来确认是否爆
在
-ftrapv
代替。
24.Tree\ DP
树上DP如果与距离相关,有一个比较好的想法/套路:
考虑按照每个点统计的子树内各个距离的DP值来转移,边转移边统计答案可以考虑好所有子树内的情况,只要这样转移到根就可以统计好所有的情况了,不需要考虑祖先。
25.EXtended\ China\ Remainder\ Theorem
扩展中国剩余定理适用于任意模数下的CRT。
我们只考虑两个式子的合并:
我们先改变一下形式,变成
然后两式合在一起
同除
移项
新的
似乎除
MA
26.EXtended\ Lucas\ Theorem
首先卢卡斯定理不是没用了,它更多地是把一个数化为
扩展卢卡斯主要用来解决
我们让但我不太会普通
然后我们可以用一些操作来求
对于一个阶乘
需要注意的是由于我们算阶乘的每次递归都忽略了
27.Fibonacci\ Sequence
斐波那契数列性质太多了,这里整理一些。
注意这里的斐波那契数列指的是
矩阵
前缀和
性质
两个斐波那契数列加起来还是一个斐波那契数列。
(此条成立当且仅当
28.Polynomial
多项式部分详见我的总结slide。
29.Lagrange\ Interpolation
拉格朗日插值法是个虽然很naive但我总是记不住的东西。现在终于可以写下来了。
1.暴力拉格朗日插值法
考虑知道一个
实际上我们相当于求这个多项式的系数。
我们可以构造
尝试一下:
于是我们要求的多项式就可以线性结合了。
用这种方式构造自然是
2.重心拉格朗日插值法
注意:在数学中这被成为重心拉格朗日插值公式第一型,也就是说,这并不是真正的重心拉格朗日插值公式。但在OI中,这个大概够用了。
有没有办法优化这个做法呢?
我们发现上面的式子有重复的部分,那么可以优化一下形式。
我们会发现这个式子还是是有一些性质的:
对于动态加点的插值来说这是啥啊,我们只需要分别用
而对于横坐标连续(整数连续)的点值,我们可以进行一些优化,来达到整个式子
简单来说,你可以发现
自然数幂和是这个方法的一个经典应用。也就是求
我们设
这其实是一个
然后直接插值就可以了?只要不想错式子就没有问题。
3.拉格朗日插值的性质
详细可以去看
大概只需要记住这样的
4.增加速度
其实是可以快速插值插出个多项式的。时间复杂度是
5.如何实现
我后来发现我好像经常忘记如何实现插值,就稍微讲一下。
就是你直接把
然后就对着式子艹就可以了。
30.Li\ Chao's\ Segment\ Tree
李超线段树专门用来解决维护一些
在一类
李超线段树运用了标记永久化的思想来保证复杂度,插入线段的复杂度是
具体的实现如下:
对于线段树上的每一个区间,我们维护这个区间在中点是的就是这么随意而不是网上许多人说的面积最大,这可以也只能保证它在这个区间内绝对有一块区域是不会被其他线段覆盖的。
我们先来考虑查询操作。同标记永久化的其它线段树一样,查询的区间要考虑到上面区间的影响。
但这里并不需要那么麻烦,在
再来考虑如何插入一条线段。每次进入完全的子区间时,我们用一个
首先我们先
然后我们找一下两条线段的交点,如果在区间外,说明优势线段在整个区间都很优秀,直接
否则如果在区间左边,我们就往左递归,否则就往右递归。
于是插入的复杂度就是
这样我们就完成了维护。
注意交点这个东西可能精度有点问题,而且在
因此我们换一种搞法:首先还是
那么如果
有一道板子题是