今天中午,老师带领我们改变了学习策略。要先学习知识点,看题解,学习做题技巧和方法,然后再自己做题,这时候,就算做不出题来,也不能看那题解,同学之间互相商量,找出程序中的不足并解决它。 

          我先要制定自己的学习计划,我打算看第一个人的博客的时候,要慢慢看,把所有关于这个知识点的方法都掌握牢固,再接着看下一个,这样再看下一个人的博客时,很多相同类型的题,可能看一眼就知道怎么回事了,只需看一下需要注意的地方就可以了,把题浏览一遍估计这道题就算是看完了。

          我今天把昨天看的基础知识点又回看了一遍,一是因为感觉掌握的不牢固,二是要看博客了,要把所以得基础知识牢记在心才可以。下面就是我今天的主要收获了,也是我记得笔记,在这里存起来,下次忘记的时候方便查阅。


 一。---树状数组的基本函数。

              1。lowbit()------算出a&(-a)

              2。add()-------更新操作,当有某个值添加或者删除(增加或减少)的时候用。

              3。sum()--------求和,sum(i)表示a[1]到a[i]的和。也可以求a[i]的值。


 二。----基础操作----区间更新,单点求和。

               当[a,b]区间加1时。

               可以         add(a,1);从这之后的sum()都会加1。

                               add(b+1,-1);   从这之后的sum()都会减1。也就是从这之后原来的加一被抵消了。

               这样原来的求和数组已经不是原来的意义了,这已经不是为了求和了。

               这时候在区间[a,b]内求一个值sum(i)会比原先加1.


 三。----基础操作------单点更新,区间区和。


当需要a[i]增加d时,

可以       add(a[i],d);

这样   当 x > i 时,sum(x)求和都增大了d。

求和时,求区间[ j , k  ] 的和,sum(k)- sum(j-1);


四----离散化


离散化一般都要定义结构体,结构体里一般包含两个数,一个数是输入的原值 v ,一个数是记录输入的先后次序的  id。

1。在输入数据时,要便输入边对结构体的 id 进行赋值,从1到n。(输入的先后顺序)

2。根据结构体中数据的大小进行排序。(排序)

3。新建立一个数组b,结构体的 id  作为数组下表,然后,根据排序的先后顺序,给数组b赋从1到n的值代表他们原来的大小关系。(大小的代换)

离散化完毕,现在这些不集中的数据,已经变得集中了。在处理数据大,数据量不大的数据时可以采用离散化。


五-----顺序对 (在b[ i ]前面,比b[ i ]小的数的数量)


当离散化完毕后会得到一个数组  b[ i ] ,   b[ i ] 代表原来值的大小,  i  代表输入的先后顺序。(没有离散也是一样的)

求顺序对时,

先求加和          ans+=sum(b[ i ]);

后更新             add(b[ i ] ,1);

sum(b[ i ])  是比b[ i ]先进入数组 且 比 b[ i ]要小的数,也就是以b[ i ]结尾的顺序对的数量。

ans   就是全部的顺序对的数量。


六-------逆序对(在b[ i ]前面,比b[ i ]大的数的数量)


当离散化完毕后会得到一个数组  b[ i ] ,   b[ i ] 代表原来值的大小,  i  代表输入的先后顺序。(没有离散也是一样的)

先更新             add(b[ i ] ,1);

后求加和          ans+=n-  sum(b[ i ]);

n是此时进入数组的数的数量。

sum(b[ i ])  是比b[ i ]先进入数组 且 比 b[ i ]要小的数。

两者相减就是比b[ i ]先进入数组 且 比 b[ i ]要大的数。(就是以b[ i ]结尾的逆序对的数量)

ans   就是全部的逆序对的数量。


当看完了这个我曾经想过,到底有没有三对上升,或者四对,甚至n对那。果然,那是有的。


七----三对顺序或者逆序。


当一个数存入数组用1来表示,没有存入用0来表示,本身这个树状数组就不是求和了。

因为树状数组的sum1(k)操作,取出的数字,表示比 k  先进入数组的,比k 小的数的个数,也就是输入时,排在k前面比 k 小的数的个数。这是,按照输入顺序放入树状数组的情况。

当倒着把数据放入树状数组时,sum2( k ),取出的数字,就是排在 k 后面的,比k 小的数字的个数。

那么当正着输入时   max1=k - sum1(k)

倒着输入时   max2= n - sum2(k)

此时,max1就是排在 k 前面比k大的数的个数。

max2就是排在 k 后面比 k 大的数的个数。(这个原因在六,逆序对中有)

最后的总数就是   sum1(k)*max2+sum2(k)*max1;


八-----连续上升或下降的n元子序列的求法。(这里说四元上升子序列)


可能用到的知识点   1.离散化(如果数据过大)2 dp(当n>3)时,比如现在是四。3 树状数组  (n个)  4 高精度(如果64位都不够用的话)

输入数据为a[ i ]。

下面的   x  y都是a [ i ] 。。。  sum()不是树状数组的函数了,是对里面的所有符合条件的数组求和。

dp过程

dp[ x ][ 2 ] = sum(dp[ y ][ 1 ]);

dp[ x ][ 3 ] = sum(dp[ y ][ 2 ]);

dp[ x ][ 4 ] = sum(dp[ y ][ 3 ]);

其中dp[ x ][ 2 ]  表示的意思是,x为子序列最后一个数字时的二元上升子序列的个数。

因为所有的3元都是来自于之前的二元,所以可以用这个来实现。

其中的树状数组有n个,每次输入一个数据,都需要对所有的树状数组进行更新。


九-----求逆序的一个有意思的题型。(这种题需要离散化之后再做)


从1到n有n个数,叫做 a[ i ] ,杂乱的排成一行,可以算出他们的逆序对数的综合 ans ,但是,现在你需要把a[ 1 ]放到a[ n ]后面,然后再算逆序对数,下一步,把现在的a[ 1 ]放到后面,再算一次,知道循环完毕。要求算出最小的逆序对数。

这时,我们先按照算逆序对数的正常思路,算出ans,

如果第一个移动到最后的时a[ 1 ],在除了a[ 1 ]的所有数中,比a[ 1 ]小的数的个数min=a[ 1 ]-1;

                                                                                                         比a[ 1 ]大的数的个数max=n-a[ 1 ];

但是,移动的时候,关于a[ 1 ]的逆序对数改变了,当然其他的没变,原来比它小的,变成了顺序,比它大的变成了逆序。

也就是ans+=max-min;这样就求出了在这一次移动中,ans的变化,然后我们只需要让它循环n-1次,就求出了最小的ans(逆序对的个数)。

这种方法的关键就是a[ i ]是由1到n的,就是需要离散化。


今天学习的主要内容就是这些了,我把我记录的书面笔记,比较条理的整理了一遍,复习了一遍,很多记得不是很清楚的地方都变得清楚了,通过今天一天的学习,我的收货很大,希望我能不断汲取知识,不断成长,让我的内力越来越深厚,招式越来越复杂。

祝明天更美好。