本文是作者看不懂分治FFT之后开始娱乐一下自己写的

看到一道题时候询问了正解后,推出了一个奇怪的变换,发现这个很Transformation,我和正解推出来的奇怪的东西是一样的,但还是想写一下思路。。。

(希望原题作者不要来D我啊)

min卷积和max卷积

考虑两个卷积

\(C_{min(i,j)} = \sum_{i = 1}^{n}\sum_{j = 1}^{n} A_{i}B_{j}\)

\(C_{max(i,j)} = \sum_{i = 1}^{n}\sum_{j = 1}^{n} A_{i}B_{j}\)

普通的卷积,即我们对下标进行加法操作后,将两个数的乘积加到该下标,在这里对下标的操作即使取min和取max

和暴力卷积一样,这两个卷积是可以暴力\(n^2\)出解的,但是有没有更优秀的做法呢

一种变换的出现,往往都是要把卷积变成点积,再用点积反解多项式的系数

例如FFT是插入函数值,利用两个函数相乘的结果,某个x坐标上的值即对应两个函数值的乘积,再利用单位根的特殊性质将系数解出来

例如FWT的异或卷积,我们要达成的成就就是\(tf(A)* tf(B) = tf(C)\),按最高位是0或1来分组,那么就是\(C = (A_{0}*B_{0} + A_{1}*B_{1},A_{0} * B_{1} + A_{1} * B_{0})\),按照点积等于卷积后的答案,构造两个乘法使得可以得到其中的每一项,即为\((A_{0} + A_{1})(B_{0} + B_{1}) = A_{0}B_{0} + A_{0}B_{1} + A_{1}B_{0} + A_{1}B_{1}\)和\((A_{0} - A_{1})(B_{0} - B_{1}) = A_{0}B_{0} - A_{1}B_{0} - A_{0}B_{1} + A_{1}B_{1}\)

两项相加除二即为前半段,相减除二即为后半段,两个变换即为\((tf(A_{0}) + tf(A_{1}),tf(A_{0}) - tf(A_{1}))\)复杂度\(O(n \log n)\)由于\(n\)往往是\(2^{k}\)所以复杂度会被写成\(O(2^{k}k)\)

所以我们尝试把这个卷积进行同样的操作

(然而很多变换的方式都是不知道为啥试出来的)

对于min卷积

我们考虑变换\(C(i)\)为\(SC(i)\),\(SC(i)\)表示\(x>=i\)的\(C(x)\)的和,\(SA(i)\)与\(SB(i)\)同理

然后即可发现\(SA(i) * SB(i) = SC(i)\),最后差分即可还原C数组,复杂度做到了\(O(n)\)

对于max卷积

我们考虑变换\(C(i)\)为\(SC(i)\),\(SC(i)\)表示\(x<=i\)的\(C(x)\)的和,\(SA(i)\)与\(SB(i)\)同理

然后即可发现\(SA(i) * SB(i) = SC(i)\),最后差分即可还原C数组,复杂度做到了\(O(n)\)

数组的标准分解意义下多维后缀/前缀和

我们如果把一个数的标准分解(即质因数分解)作为这个数的坐标,例如

\(p_{1}^{k_{1}}p_{2}^{k_2}p_{3}^{k_{3}}...p_{n}^{k_{n}}\)

每个数即可看做一个无穷维度里,每一个维度的下标为该质因数的指数的一个坐标

数组的多维前缀和即

\(f(n) = \sum_{d|n}a(d)\)

数组的多维后缀和即

\(f(n) = \sum_{n|d}a(d)\)

朴素的做法可以达到\(O(n \log n)\),可以过很多题目了,即对于一个数枚举它的倍数(用调和级数算复杂度也是一个重要的技巧)

我们考虑如何将这个算法优化到\(O(n \log \log n)\)

我们以前缀和为例,从最小的质因子2开始,固定其他所有质数的指数,开始考虑以下这个过程

1:a(1)

2:a(2)

3:a(3)

4:a(4)

5:a(5)

6:a(6)

7:a(7)

8:a(8)

9:a(9)

10:a(10)

初始化即每个数组位置存储对应的a(i)

第一次操作2,从后往前扫,我们对每个2的倍数进行累加,具体看下面

1:a(1)

2:a(2) a(1)

3:a(3)

4:a(4) a(2) a(1)

5:a(5)

6:a(6) a(3)

7:a(7)

8:a(8) a(4) a(2) a(1)

9:a(9)

10:a(10) a(5)

第二次操作3

1:a(1)

2:a(2) a(1)

3:a(3) a(1)

4:a(4) a(2) a(1)

5:a(5)

6:a(6) a(3) a(2) a(1)

7:a(7)

8:a(8) a(4) a(2) a(1)

9:a(9) a(3) a(1)

10:a(10) a(5)

第三次操作5

1:a(1)

2:a(2) a(1)

3:a(3) a(1)

4:a(4) a(2) a(1)

5:a(5) a(1)

6:a(6) a(3) a(2) a(1)

7:a(7)

8:a(8) a(4) a(2) a(1)

9:a(9) a(3) a(1)

10:a(10) a(5) a(2) a(1)

第四次操作7

1:a(1)

2:a(2) a(1)

3:a(3) a(1)

4:a(4) a(2) a(1)

5:a(5) a(1)

6:a(6) a(3) a(2) a(1)

7:a(7) a(1)

8:a(8) a(4) a(2) a(1)

9:a(9) a(3) a(1)

10:a(10) a(5) a(2) a(1)

下一个质数是11,已经超出了范围,所以操作完成了,至此,我们已经完成了数组的多维前缀和

下面以相同的例子理解数组的多维后缀和

第一次操作2,从后往前扫

1:a(1) a(2) a(4) a(8)

2:a(2) a(4) a(8)

3:a(3) a(6)

4:a(4) a(8)

5:a(5) a(10)

6:a(6)

7:a(7)

8:a(8)

9:a(9)

10:a(10)

第二次操作3

1:a(1) a(2) a(4) a(8) a(3) a(6) a(9)

2:a(2) a(4) a(8) a(6)

3:a(3) a(6) a(9)

4:a(4) a(8)

5:a(5) a(10)

6:a(6)

7:a(7)

8:a(8)

9:a(9)

10:a(10)

第三次操作5

1:a(1) a(2) a(4) a(8) a(3) a(6) a(9) a(5) a(10)

2:a(2) a(4) a(8) a(6) a(10)

3:a(3) a(6) a(9)

4:a(4) a(8)

5:a(5) a(10)

6:a(6)

7:a(7)

8:a(8)

9:a(9)

10:a(10)

第四次操作7

1:a(1) a(2) a(4) a(8) a(3) a(6) a(9) a(5) a(10) a(7)

2:a(2) a(4) a(8) a(6) a(10)

3:a(3) a(6) a(9)

4:a(4) a(8)

5:a(5) a(10)

6:a(6)

7:a(7)

8:a(8)

9:a(9)

10:a(10)

由于对每个质数枚举倍数(根据埃拉托斯特尼筛法的复杂度)是\(O(n \log \log n)\)的

所以求数组的标准分解意义下的多维前缀和,后缀和可以做到\(O(n \log \log n)\)

Fast GCD Transformation 快速最大公约数变换

由于两个数的GCD,即为两个数标准分解下的每个质因数质数取min,即为

\(p_{1}^{min(a_{1},b_{1}}p_{2}^{min(a_{2},b_{2})}...p_{k}^{min(a_{k},b_{k})}\)

类似min卷积,将数组处理成多维后缀和,即为正变换

考虑如何将变换后的结果还原回去

sc数组中点积相乘的结果即为

1:c(1) c(2) c(3) c(4) c(5) c(6) c(7) c(8) c(9) c(10)

2:c(2) c(4) c(6) c(8) c(10)

3:c(3) c(6) c(9)

4:c(4) c(8)

5:c(5) c(10)

6:c(6)

7:c(7)

8:c(8)

9:c(9)

10:c(10)

考虑如何将他们变换回去,我们发现可以采取我们累加后缀和的步骤反序进行

即,从大到小枚举质数,从前往后枚举下标

第一次枚举7

sc数组中点积相乘的结果即为

1:c(1) c(2) c(3) c(4) c(5) c(6) c(8) c(9) c(10)

2:c(2) c(4) c(6) c(8) c(10)

3:c(3) c(6) c(9)

4:c(4) c(8)

5:c(5) c(10)

6:c(6)

7:c(7)

8:c(8)

9:c(9)

10:c(10)

第二次枚举5

1:c(1) c(2) c(3) c(4) c(6) c(8) c(9)

2:c(2) c(4) c(6) c(8)

3:c(3) c(6) c(9)

4:c(4) c(8)

5:c(5) c(10)

6:c(6)

7:c(7)

8:c(8)

9:c(9)

10:c(10)

第三次枚举3

1:c(1) c(2) c(4) c(8)

2:c(2) c(4) c(8)

3:c(3) c(6)

4:c(4) c(8)

5:c(5) c(10)

6:c(6)

7:c(7)

8:c(8)

9:c(9)

10:c(10)

第四次枚举2

1:c(1)

2:c(2)

3:c(3)

4:c(4)

5:c(5)

6:c(6)

7:c(7)

8:c(8)

9:c(9)

10:c(10)

复杂度同样为\(O(n \log \log n)\),同时我们可以发现,数组标准分解意义下的多维后缀差分即使前缀和的逆步骤

同时,如果了解莫比乌斯反演,会列出等式

\(sc(n) = \sum_{n|d}c(d)\)

\(c(n) = \sum_{n|d}\mu(\frac{d}{n})sc(d)\)

即,该差分本质上是对\(sc(i)\)进行莫比乌斯反演,我们又得到了一种\(O(n \log \log n)\)求解莫比乌斯反演的办法,而并非\(O(n \log n)\)

Fast LCM Transformation 快速最小公倍数变换

我们发现LCM即对两个下标标准分解的每个质因数取max,即

\(p_{1}^{max(a_{1},b_{1})}p_{2}^{max(a_{2},b_{2})}...p_{k}^{max(a_{k},b_{k})}\)

但是由于LCM的性质,我们下标的范围会达到\(n^{2}\),比暴力好不到哪里,所以讨论起来就没有太多意义

如果我们强制限定长度在N范围内,即变换成数组标准分解的多维前缀和,最后多维前缀差分还原回去,类似FGT

FGT的代码

for(int i = 1 ; i <= tot ; ++i) {
for(int j = N / prime[i] ; j >= 1 ; --j) {
a[j] += a[j * prime[i]];
b[j] += b[j * prime[i]];
}
}
for(int i = 1 ; i <= n ; ++i) {
c[i] = a[i] * b[i];
}
for(int i = tot ; i >= 1 ; --i) {
for(int j = 1 ; j <= N / prime[i] ; ++j) {
c[j] -= c[j * prime[i]];
}
}

O(n log log n)实现FGT和FLT(Fast GCD/LCM Transformation)的更多相关文章

  1. 浅谈 van Emde Boas 树——从 u 到 log log u 的蜕变

    本文参考算法导论完成. 模板题在此 QwQ 优化的过程比较长,还请读者耐心阅读,认真理解. 最初的想法 我会暴力! 用一个 \(size\) 数组维护每个元素出现的次数. 不细讲,时间复杂度 \(O( ...

  2. Android将应用调试log信息保存在SD卡

    转载:http://blog.csdn.net/way_ping_li/article/details/8487866 把自己应用的调试信息写入到SD卡中. package com.sdmc.hote ...

  3. 【msql】关于redo 和 undo log

    InnoDB 有两块非常重要的日志,一个是undo log,另外一个是redo log,前者用来保证事务的原子性以及InnoDB的MVCC,后者用来保证事务的持久性.和大多数关系型数据库一样,Inno ...

  4. VC++ 一个简单的Log类

    在软件开发中,为程序建立Log日志是很必要的,它可以记录程序运行的状态以及出错信息,方便维护和调试. 下面实现了一个简单的Log类,使用非常简单,仅供参考. // CLogHelper.h : hea ...

  5. JFinal - Log 日志

    今天偶然发现 JFinal 的 Log 简单小巧.上代码. JFinal 在初始化的时候有初始化 Log. class Config { // ... static void configJFinal ...

  6. 自定义javascript log方法

    /** * 类似chrome,firefox的console对象 * 但是在IE等不支持console的浏览器不会报错 * 理论上浏览器支持的console的方法都支持,比如谷歌的 * assert, ...

  7. [蓝牙] 6、基于nRF51822的蓝牙心率计工程消息流Log分析(详细)

    开机初始化Log Log编号 函数名   所在文件名 000001: main ..\main.c 000002: timers_init ..\main.c 000003: gpiote_init ...

  8. python log

    python的日志模块为logging,它可以将我们想要的信息输出保存到一个日志文件中. # cat log import logging logging.debug('This is debug m ...

  9. SeasLog-An effective,fast,stable log extension for PHP

    github: https://github.com/Neeke/SeasLog @author Chitao.Gao [neeke@php.net] @交流群 312910117 简介 为什么使用S ...

随机推荐

  1. Camera ISO、快门、光圈、曝光这几个概念

    转载自知乎:https://www.zhihu.com/question/21427664 种田要知节气,开车要懂离合,任何一样手艺都有行话.虽然我觉得尽量从实际问题说起,尽量不要说的很专业,但有几个 ...

  2. linux服务器上修改oracle数据库的字符集

    linux服务器上以dba身份进入:sqlplus / as sysdba; 依次执行以下命令:shutdown immediate; startup mount; alter system enab ...

  3. 在 iPad 上试验从用算法生成法线贴图-到法线映射光照效果

    在 iPad 上试验从用算法生成法线贴图-到法线映射光照效果 目录 概述 一般来说, 法线贴图是用高模的法线图, 低模的纹理图, 来生成较好的渲染效果. 而法线图通常是通过图像处理软件来生成的, 这里 ...

  4. Java并发编程原理与实战三十八:多线程调度器(ScheduledThreadPoolExecutor)

    在前面介绍了java的多线程的基本原理信息:线程池的原理与使用 本文对这个java本身的线程池的调度器做一个简单扩展,如果还没读过上一篇文章,建议读一下,因为这是调度器的核心组件部分. 我们如果要用j ...

  5. nodejs 剪切图像在上传,并保存到指定路径下(./public/img/' + req.session.token + '.jpg‘)

    前jQuery端接收数据 function upAvatar(img){ console.log(img); // data:image/jpeg;base64,/9j/4AAQSkZJRgABAQA ...

  6. Asp.net 中,在服务端向客户端写脚本的常用方法

    在Asp.net 服务端处理脚本,一般都用 ClientScriptManager ,即web窗体服务端的this.ClientScript.该对象比较常用的方法: 1.RegisterArrayDe ...

  7. SVN自动更新-win平台

    把项目给外包做,他们天天整个ftp传来传去,上传一次还要到处翻View和Controller,还有漏传的情况,简直low到不行.看不下去了,就准备整个svn.虽然svn解决了上传的问题,但是自动发布还 ...

  8. HDU 1027 Ignatius and the Princess II 排列生成

    解题报告:1-n这n个数,有n!中不同的排列,将这n!个数列按照字典序排序,输出第m个数列. 第一次TLE了,没注意到题目上的n和m的范围,n的范围是小于1000的,然后m的范围是小于10000的,很 ...

  9. 【leetcode 简单】 第六十三题 使用队列实现栈

    使用队列实现栈的下列操作: push(x) -- 元素 x 入栈 pop() -- 移除栈顶元素 top() -- 获取栈顶元素 empty() -- 返回栈是否为空 注意: 你只能使用队列的基本操作 ...

  10. ASP.NET 网站部署到IIS上如何进行调试

    1:在一个网站成功部署后,有可能会遇到一些错误,但是又不能直接看出错误源(如果能在源程序里下断点进行调试就好了,这样就能准确的找出错误代码),下面介绍如何在一个已经部署的网站上进行断点调试(前提有网站 ...