【gdoi2018 day1】密码锁

这一题的正解是差分。

设dif[i]=a[i+1]-a[i],(0<=i<=n),默认a[0]=a[n+1]=0。当然,dif[i]是在模m的意义下的。

我们的原目标是把a数组清成0,而若a全为0,则dif也全为0。反之,若dif全为0,则a全为0,因为a[1]=a[0]+dif[0]=0,a[2]=a[1]+dif[1]=0……,以此类推。那么我们现在的任务就是要把dif清成0.

那么我们考虑一下对[l.r]这个区间进行操作时对dif的影响。若我们把[l.r]加1,则dif[l~r-1]都不会变,会变的是a[l-1]和a[r],a[l-1]会加1,而a[r]会减1.把[l,r]减1的情况也类似,就是a[l-1]会减1,而a[r]会加1.

这就是操作的影响,显然问题一定有解,那答案怎样求呢?由于每次操作只会对dif中的两个数造成影响,所以我们可以贪心,具体策略就是把dif较小减成0,把dif较大的加成m。所以我们可以把dif从小到大排个序,然后枚举一个加和减的分界线,那怎样求答案呢?假设当前情况是dif[0~i]要减,dif[i+1~n]要加,则首先要保证这种情况有解。

这个怎样判断呢?我们发现,每一次操作都是dif中一个数减一,一个数加一,而任意一个dif[i]是不会既被加过又被减过的(这样就重复了),所以我们就可以把每一次操作看成是一个被加的dif与一个被减的dif的配对,最后直至每一个dif都为0。所以判断条件就是sum(dif[j])==sum(m-dif[k]),0<=j<=i,i+1<=k<=n。而答案就是sum(dif[j])了,因为一共要配对这么多次。

总结差分:

差分就是把一个数组中相邻的两个数做差得到的新数组,它主要就是利用对一个区间同加或同减时只有这个区间的头和尾会变化,从而简化修改操作。如果遇上对一个区间进行同加或同减操作时,不妨考虑一下差分。

你可能感兴趣的:(算法)