zoukankan      html  css  js  c++  java
  • 差分

    差分

    差分:两个相邻的数之差。

    把原数列进行差分,得到新数列,这是1阶差分。

    把新数列再差分,得到2阶差分的数列。

    以此类推,进行n次差分后,得到的数列就是n阶差分。

    应用:

    用于解决有规律的区间问题,

    例如区间加等差数列,给(xin[L,R])加上((x - L) * d),

    2阶差分下的等差数列就可以转化为普通的差分问题(+1), (-1)

    通常需要找到数列在n阶差分下变成简单差分问题,再进行从(n)(0)阶用前缀和还原,还要注意(n)阶差分在(1)(n)阶的影响要消除

    树上差分:

    点权:

    (u,v) ,(+1);

    (lca,f(lca))(-1).

    边权:

    边记在较深点。

    (u,v) ,(+1);

    (lca)(-1).

    • 问题:

    P4231 三步必杀

    下面 (a_{i,j}) 表示 (a) 经过 (i) 次差分后第 (j) 位的数。

    区间对([L, R])加上(s, ..., e)的等差数列。

    一个等差数列(y = d(x-1) + s),容易发现是一次函数,进行一次差分就变成常数,对常数差分就变成(0)((y''=0))

    原数列({1,2,3,4,5})

    一次差分({1,1,1,1,1})

    二次差分({1,0,0,0,0})

    有操作([1,3],s=2,e=4),那么这个等差数列是({2,3,4}),公差(d = 1)

    一次差分得到({2,1,1}),这是在一阶差分数组对区间([1,3])加上(2,1,1)

    在差分得到({2,-1,0}),发现就能在原数组的二阶差分下,对(a_{2,1}+1),对(a_{2,2} - 1)(a_{2,3 + 1} - (2 - 1)).

    二阶差分({3,-1,0,-1,0,0})

    一阶差分({3,2,2,1,1})

    原数组({3,5,7,8,9})

    发现多了好多,这是没有消除影响的结果。

    这时一阶为({3,2,2,1,1})

    在对(a_{2,3 + 1} - (2 - 1))的同时,也要对(a_{1,3+1}- sum), (sum) 为询问操作在一阶差分的区间([1,3])的和(2 + 1 + 1=4)

    这时一阶为({3,2,2,1 - 4,1})

    还原,原数组({3,5,7,4,5}),即({1+2,2+3,3+4,4,5})

    在本题题解中,也有把这些影响化简的方法,就能只在二阶差分数组操作。

    CF407C Curious Array

    (forall xin[L,R]subset Z, x + inom{x - L + k}{k})

    简单的变换(inom{x-L+k}{k} = inom{x-L+k}{x-L})

    对于一个组询问((L,R,k)),就加(inom{k}{0}),(inom{k + 1}{1}),(...),(inom{k + R - L}{R - L}).

    在杨辉三角里,这就是一条起点是((k, 0))终点是((k + R - L, R - L))的线段,正好是(45)°。

    我们知道

    [inom{n}{m} = inom{n -1 }{m} + inom{n - 1}{m - 1} ]

    移项得到

    [inom{n}{m} -inom{n - 1}{m - 1} = inom{n -1 }{m} ]

    发现上面

    [inom{k}{0},inom{k + 1}{1},...,inom{k + R - L}{R - L} ]

    与这条式子很像。

    就把它差分一次,得到

    [inom{k}{0},inom{k}{1},...,inom{k + R - L - 1}{R - L} ]

    这个

    [inom{k}{0}=inom{k-1}{0}=1 ]

    这样换一下就漂亮多了:

    [inom{k - 1}{0},inom{k}{1},...,inom{k + R - L - 1}{R - L} ]

    再差分:

    [inom{k - 2}{0},inom{k - 1}{1},...,inom{k + R - L - 2}{R - L} ]

    那么差分了(j)次,就得到:

    [inom{k - j}{0},inom{k + 1 - j}{1},...,inom{k + R - L - j}{R - L} ]

    当差分了(k + 1)次,

    [inom{k - (k + 1)}{0} = inom{-1}{0},inom{k - (k + 1) + 1}{0} = inom{0}{1},... ]

    这时所有数都为(0),再差分也没有意义了。

    • 考虑经过(k + 1)次差分后,得到全0的数列。

    • 假如给第(L)数也就是这个数列的第一个数(+1)

      这里(inom{k - k}{0} = 1)

      到了第二个数,求前面两个数的和,((1 + inom{k-(k + 1)}{0}) + inom{k-(k+1) + 1}{1} = inom{k - k}{0} + inom{k-k}{1}=inom{k - k + 1}{1})这就是(K)次差分数组的第二个数。

    • 以此类推,只要给(a[k+1][L] +1),就能推出(a[k][L...N])

      那么在(R+1)位置(-1),就能不改变(R+1)后面的位置了,即算出了 (a[k][L...R])

    • 这样算就发现(a[k - 1][R...N])多了,推出上一阶的差分数组时要考虑有没有算多,考虑 (K) 次差分在 (K - 1) 次差分的影响,这就是在 (K - 1) 次差分的 (R+1) 位置,减去这次加入的数列([L,R])(K)次差分下的和。

      总的来说,就是对
      $$forall K in [1,k + 1], a[K][R+1] - sum$$

      这个数列在(K)次差分下为(inom{k - K}{0},inom{k + 1 - K}{1},...,inom{k + R - L - K}{R - L}).

      $$a[K][R + 1] - (inom{k - K}{0} + inom{k + 1 - K}{1} + ... + inom{k + R - L - K}{R - L})$$
      通过证明,
      $$inom{k - K}{0} + inom{k + 1 - K}{1} + ... + inom{k + R - L - K}{R - L} = inom{K + R - L - K + 1}{R - L} $$

      感性理解一下,

      在杨辉三角里,就是一条起点是((k, 0))终点是((k + R - L, R - L))的线段,

      [inom{k}{0}=inom{k + 1}{0} = 1 ]

      这个式子相当于把起点((k,0))移到((k + 1, 0)),

      再通过

      [inom{k}{i}+inom{k}{i + 1} = inom{k + 1}{i + 1} ]

      这个式子,把这两个点合成((k + 2,1)),在与((k+2,2))合成((k + 3,2))......最后就合成到

      [inom{K+R-L-K+1}{R-L} ]

    • 所以,对(forall K in [1,k + 1], a[K][R+1] - inom{K+R-L-K+1}{R-L})

      最后就是从(K+1)次差分开始,第(i)次差分通过前缀和,得到(i - 1)的差分,最后得到原数组啦。

      CF上用C++14还要把用来差分的数组清零,不然有奇怪的值?

    P4868 Preprefix sum

    (O(log n))的时间内,知道了二阶差分,求出原序列某一位。

    求原序列的(x)位,

    [a_x = sum_{i=1}^{x}sum_{j=1}^{i}c_j ]

    (c)为二阶差分,(b)为一阶差分,那么(b_i = sum_{j=1}^{i}c_j)

    考虑(c_j)会被(a_x)计算几次,首先(c_j)会对(b_j)及以后的(b)产生贡献,

    其中贡献到(a_x)(b)(b_j)(b_x),因此(a_x)被贡献((x - j + 1))

    [a_x = sum_{i=1}^{x}(x - j + 1)c_j ]

    [a_x = (x + 1)sum_{i=1}^{x}c_j - sum_{i=1}^{x}j imes c_j ]

    这两个和式都能用树状数组算出。

    P4514 上帝造题的七分钟

    二维差分。

    平面求和,平面修改。

    同上题差不多的做法。

    差分定义为

    [d_{x, y} = a_{x,y} - a_{x - 1, y} - a_{x, y -1} + a_{x - 1, y - 1} ]

    和二维前缀和相同。

    [a_{x,y}=sum_{i=1}^{x}sum_{j=1}^{y}sum_{a=1}^{i}sum_{b=1}^{j}d_{a,b} ]

    求a的((1,1))((x,y))的和。

    考虑差分(d_{i,j})的贡献,只有(a_{k,z}|kin[i,x],zin[j,y])算入(d_{i, j})

    那么(d_{i,j})被计算((x-i+1)(y-j+1))次.

    [a_{x,y}=sum_{i=1}^{x}sum_{j=1}^{y}(x - i + 1)(y - j + 1)d_{i,j} ]

    [a_{x,y}=sum_{i=1}^{x}sum_{j=1}^{y}(xy-xj-x-iy+ij-i+y-j+1)d_{i,j} ]

    [a_{x,y}=sum_{i=1}^{x}sum_{j=1}^{y}((xy+x+y+1)+ij-i(y+1)-j(x+1))d_{i,j} ]

    [a_{x,y}=(xy+x+y+1)sum_{i=1}^{x}sum_{j=1}^{y}d_{i,j}+sum_{i=1}^{x}sum_{j=1}^{y}ijd_{i,j}-(y+1)sum_{i=1}^{x}sum_{j=1}^{y}id_{i,j}-(x+1)sum_{i=1}^{x}sum_{j=1}^{y}jd_{i,j} ]

    用四个二维树状数组记录(d_{i,j},i imes d_{i,j},j imes d_{i,j},i imes j imes d_{i,j})

    时间复杂度(O(qlog^2n))

  • 相关阅读:
    PDB文件详解
    C++模板常用功能讲解
    Windows下多线程编程(二)
    关于静态库中使用全局变量可能导致的问题
    js中的函数
    js中字符串的加密base64
    列表推导式
    函数和方法的区别
    xshell连不上虚拟机
    网络编程,并行,并发和协程
  • 原文地址:https://www.cnblogs.com/qjbqjb/p/15425117.html
Copyright © 2011-2022 走看看