首页 > 其他分享 >Fast Möbius Transform 学习笔记

Fast Möbius Transform 学习笔记

时间:2024-04-24 22:34:56浏览次数:12  
标签:... 前缀 i1 sum i2 Transform Fast hat bius

小 Tips:在计算机语言中 \(\cup\) = & / and, \(\cap\) = | / or

First Step. 定义

定义长度为 \(2^n\) 的序列的 and 卷积 \(A = B * C\) 为 \(A_i=\sum_{j \cup k = i}{B_j*C_k}\)

考虑快速计算

Second Step. 变换

定义长度为 \(2^n\) 的序列的 Zeta 变换

\[\hat{A}_i = \sum_{j \subseteq i}{A_j} \]

即子集和

它具有一下性质:

\[\hat{B}_i \times \hat{C}_i = \sum_{j \subseteq i} B_j \times \sum_{k \subseteq i} C_k = \sum_{p \subseteq i} \sum_{j \cup k = p} B_j \times C_k = \sum_{p \subseteq i} A_p = \hat{A}_i \]

相当于 FFT 中的点值表示法,用以加速卷积过程

Third Step. 快速变换

暴力求解 \(\hat{A}\) 最优时间复杂度为 \(3^n\),考虑加速

考虑 子集DP ,有一篇很好的博客[1],这里大概讲解一下。

其实 \(\hat{A}\) 本质上是一个高维( \(n\) 维)前缀和

如果我们要求二维前缀和,显然可以通过一下代码实现:

// 1st
for(int i=1; i<=n; ++i)
    for(int j=1; j<=m; ++j)
        	a[i][j]+=a[i-1][j];
// 2nd
for(int i=1; i<=n; ++i)
    for(int j=1; j<=n; ++j)
        	a[i][j]+=a[i][j-1];

我们发现 1st 完成后 a[i][j] 表示的是 \(\sum_{k \le i} a_{k,j}\),即 \((i,j)\) 上方的元素和

那么 2nd 便是将 \((i,j)\) 左边操作后的 \(\sum_{k \le j} a_{i,k}\) 累加到 a[i][j] 中,即完成二维前缀和


下面拓展到三维前缀和

// 1st
for(int i=1; i<=n; ++i)
    for(int j=1; j<=n; ++j)
        for(int k=1; k<=n; ++k)
            a[i][j][k]+=a[i-1][j][k];
// 2nd
for(int i=1; i<=n; ++i)
    for(int j=1; j<=n; ++j)
        for(int k=1; k<=n; ++k)
            a[i][j][k]+=a[i][j-1][k];
// 3rd
for(int i=1; i<=n; ++i)
    for(int j=1; j<=n; ++j)
        for(int k=1; k<=n; ++k)
            a[i][j][k]+=a[i][j][k-1];

类似地,1st,2nd 中处理除了第 k 平面中的二维前缀和,3rd 在立体空间中把他们加起来,成为三维前缀和


回到 Zeta 变换

\[\hat{A}_i = \sum_{j \subseteq i}{A_j} \]

如果我们用二进制 \((x_{n-1}x_{n-2}x_{n-3}\ ...\ x_2x_1x_0)_2\) 表示集合 \(i\),二进制 \((y_{n-1}y_{n-2}y_{n-3}\ ...\ y_2y_1y_0)_2\) 表示集合 \(j\)

那么 \(\hat{A}_i\) 可以被视为 \(n\) 维前缀和,即

\[\hat{A}_i = \sum_{y_{n-1}\le x_{n-1},y_{n-2}\le x_{n-2},\ ...,\ y_1\le x_1,y_0\le x_0} A_j \]

当然,下标都为 0/1

因此,我们有如下 Code:

for(int i=0; i<n; ++i)
    for(int j=0; j<(1<<n); ++j)
        if(j&(1<<i))
            a[j]+=a[j^(1<<i)];

以上 Code 的 naive 形式为:

for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i1>0) a[i1][i2][...][in]+=a[i1-1][i2][...][in];
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i2>0) a[i1][i2][...][in]+=a[i1][i2-2][...][in];
...
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(in>0) a[i1][i2][...][in]+=a[i1][i2][...][in-1];

不要质疑我代码编译不通过

因此,我们用 \(O(n2^n)\) 的时间复杂度解决了 Zeta 变换

Fourth Step. 逆变换

warning:此处不是 莫比乌斯反演

众所周知,前缀和的逆运算即为差分

我们发现,只需要先将最后一维差分,即可将序列处理为 \(n-1\) 维前缀和

for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(in>0) a[i1][i2][...][in]-=a[i1][i2][...][in-1];
...
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i1>0) a[i1][i2][...][in]-=a[i1-1][i2][...][in];
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i2>0) a[i1][i2][...][in]-=a[i1][i2-2][...][in];

但实际上因为前缀和都是无序的,因此我们直接正着做就可以啦

只需要把正变换的 += 改为 -= 就可以了

Fifth Step. 扩展

有时候,题目给的不是 \(\cup\) ,而是 \(\cap\) 怎么办?

那我们重定义 Zeta 变换 为:

\[\hat{A}_i = \sum_{i \supseteq j} A_j \]

再推一下式子:

\[\hat{B}_i \times \hat{C}_i =\sum_{i\supseteq j} B_j \times \sum_{i\supseteq k} C_k =\sum_{i\supseteq j,i\supseteq k} B_j \times C_k =\sum_{i\supseteq p} \sum_{j \cap k=p} B_j \times C_k =\sum_{i\supseteq p} A_p =\hat{A}_i \]

变换即超集和,高维后缀和

求法也很简单,只用将源代码中的 if(j&(1<<i)) 该为 if(!(j&(1<<i))) 即可


是 \(\oplus\) 怎么办?

快去学 FWT 吧

Last. 例题

再送你一个并/交集的小口诀:下并上交


  1. 高维前缀和总结(sosdp) - heyuhhh - 博客园 (cnblogs.com) ↩︎

标签:...,前缀,i1,sum,i2,Transform,Fast,hat,bius
From: https://www.cnblogs.com/lnw143/p/18156523

相关文章

  • 理解Transformer [数据挖掘深度学习]
    属性离散/连续离散属性:具有有限或无限可数个值,不一定为整数。属性hair_color、smoker、medical_test和drink_size都有有限个值,因此是离散的。离散属性可以具有数值。如对于二元属性取0和1,对于年龄属性取0到110。如果一个属性可能的值集合是无限的,但是可以建立一个与自......
  • Fastjson的toString链分析
    前言之前分析过Fastjson的getter链,忽略了toString链,现在补上,最终也是任意调用getter攻击测试packageorg.example;importcom.alibaba.fastjson.JSONObject;importcom.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;importcom.sun.org.apache.xalan.inte......
  • FasterViT:英伟达提出分层注意力,构造高吞吐CNN-ViT混合网络 | ICLR 2024
    论文设计了新的CNN-ViT混合神经网络FasterViT,重点关注计算机视觉应用的图像吞吐能力。FasterViT结合CNN的局部特征学习的特性和ViT的全局建模特性,引入分层注意力(HAT)方法在降低计算成本的同时增加窗口间的交互。在包括分类、对象检测和分割各种CV任务上,FasterViT在精度与图像吞吐......
  • fastjson导致的程序崩溃:A fatal error has been detected by the Java Runtime Enviro
    ##AfatalerrorhasbeendetectedbytheJavaRuntimeEnvironment:##EXCEPTION_ACCESS_VIOLATION(0xc0000005)atpc=0x000001da4d3ab6b3,pid=15996,tid=0x0000000000006478##JREversion:Java(TM)SERuntimeEnvironment(8.0_361)(build1.8.0_361-b09)......
  • FastWiki一分钟本地离线部署本地企业级人工智能客服
    FastWiki一分钟本地离线部署本地企业级人工智能客服介绍FastWiki是一个开源的企业级人工智能客服系统,它使用了一系列先进的技术和框架来支持其功能。技术栈前端框架:React+LobeUI+TypeScript后端框架:MasaFramework基于.NET8动态函数:基于JavaScriptV8引擎实现向量搜......
  • [基础] DETR:End-to-End Object Detection with Transformers
    名称End-to-EndObjectDetectionwithTransformers时间:22.05机构:FacebookAITL;DR文章提出一种称为DETR(DetectionTransformer)的基于Transformer的检测器,相比于传统检测器不需要NMS以及anchor,仅需要少量objectqueries就可以同时推理出所有预测结果。MethodInference......
  • Qt 从 QTransform 逆向解出 Translate/Scale/Rotate(平移/缩放/旋转)分析
    QTransform用于图形绘制,它定义了如何平移(translate)、缩放(scale)、切变(shear)、旋转(rotate)或投射(project)坐标系。注意:QTransform是作用于坐标系,不是直接作用于图形。实际运用中我们可以通过QPainter、QGraphicsView、QGraphicsItem实现图形的平移、缩放、旋转等操作,但是需要从......
  • LeetCode 1331. Rank Transform of an Array
    原题链接在这里:https://leetcode.com/problems/rank-transform-of-an-array/description/题目:Givenanarrayofintegers arr,replaceeachelementwithitsrank.Therankrepresentshowlargetheelementis.Therankhasthefollowingrules:Rankisanintegers......
  • fastapi
    FastAPI1.restful接口开发规范 2.quickstart async:表示函数内部可以使用异步 使程序可以直接运行,需要导入uvicornport:端口号,debug:开发模式,reload 3.路径操作路径指的是URL中从第一个/起的后半部分。例如:https://example.com/items/foo的路径是/items/foo......
  • 分布式文件系统FastDFS安装教程
     转载链路地址https://www.cnblogs.com/handsomeye/p/9451568.html  前言centos7x642009、vmware16pro(网络仅主机模式)安装libfastcommon获取libfastcommon安装包:wgethttps://github.com/happyfish100/libfastcommon/archive/V1.0.38.tar.gz解压安......