关于子集问题的一种解法
关于子集问题的一种解法
1.引入
给定 以及两个长度为 的序列 和 ,对于每个 求
。
对于这类不可逆的运算,常规的 无法解决,当然也可能是我太菜 。
而暴力枚举的复杂度为 无法接受,
这时候我们就需要用到分治乘法。
2.记号
以下记号借用了集合幂级数的一些内容。
考虑将长度为 序列 中下标二进制最高位为 的部分记录为 ,为 的部分记为 ,记录答案序列为 。
首先,显然 。
并且,我们有
,
注意到这时我们已经把问题分成四个长度为 的子问题,但是如果暴力分治求解复杂度还是 并且还多了一堆常数。
不过第一个式子可以做如下化简,
而 是可以在分治过程中处理的,
这是我们的分治过程为
由主定理知,该算法的复杂度为 。
如果采用合适的实现,空间复杂度可以做到 。
3.程序实现
该方法实现实际上起来异常的简单。
int a[maxN], b[maxN], c[maxN];
int dat[maxN];
void multi(int *a, int *b, int *c, int n, int *dat) {
// a,b为上文所定义,c为答案数组,dat为临时数组,用来保存a的内容,n为长度
// 由于min运算的不可逆性质,必须开个数组记录原内容
n >>= 1;
if (!n) { c[0] = min(a[0] + b[0], c[0]); return; }
multi(a, b, c, n, dat);
multi(a + n, b, c + n, n, dat);
for (int i = 0; i < n; ++i) {
dat[i] = a[i];
a[i] = min(a[i], a[i + n]);
}
multi(a, b + n, c + n, n, dat + n);
for (int i = 0; i < n; ++i)
a[i] = dat[i];
}
4.习题
FWT能做的它都能做。
貌似还没什么习题。
也许可以用 AT4168 做板子?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!