[算法]NOI竞赛:简单分治及其应用(一)

[算法]NOI竞赛:简单分治及其应用(一)

首页休闲益智最大值计算竞赛更新时间:2024-06-05

分治算法是一种思想,所以比一般算法更难使用。

1.划分问题(Divide):将原问题分成一系列子问题。

2.递归解决(Conquer):递归地解各子问题。若子问题足够小,则可直接求解。

3.合并问题(ComBine):将子问题的结果合并成原问题的解。

·给出一个长度为n的序列A.求一个和最大的连续子序列。也就是要找出一对l.r(1≤l≤r≤n).使得Ai A(i 1) … A(r-1) A,最大。·n≤10^5(最大子序列问题)

·暴力枚举:

枚举l,r,对于每对l,r计算这段子序列的和,对所有结果取最大值即为答案。

暴力计算时间复杂度为O(n^3)。

一个优化是记录前缀和,即记录S[i]=A1 A2 … Ai.那么子序列[l.r]的和即为S[r]-S[l-1]。

前缀和优化后复杂度为0(n2)。

分治解法

·设F(L.R)表示L到R这段区间内的和最大的子序列,答案就是F(1.n)。

考虑分治,假设现在要计算F(L,R).设mid=(l R)/2.可以先递归计算F(L,mid)

以及F(mid 1.R)。(划分问题,递归解决)

·注意到对于一个子序列[L.rl.L≤l≤r≤R.若l≤mid<r.那么在递归的子问题中不会考虑到这个子序列。也就是还需要找到最大的经过mid的子序列。

·由于这样的子序列的和可以表示为(Ai Ai 1 … Amid) (Amid 1 … Ar)的形式,只需找到一个l使得Ai .… Amid最大,再找到一个r使得Amid 1 … Ar最大,加起来即得到结果。

·将得到的结果与F(L.mid),F(mid 1.R)取最大值,即得到F(L,R)。(合并问题)

时间复杂度为O(nlogn)

-给出一个长度为n的序列A,输出将它从小到大排序之后的结果。-n≤10^5 (排序问题)

归并排序

·假设现在要将区间[L,R]内元素的排序,借鉴之前的思想,我们可以令mid=(L R)/2,先递归地将[L.mid]和[mid 1.R]内的元素分别排好序。

现在需要将两边的序列合并在一起,可以维护两个指针p.q.一开始令p=L,q=mid 1.并建立一个序列B表示新的序列。若A[p]<A[q].则将A[p]加入B的末尾,并令p=p 1.否则将A[q]加入B的末尾,并令q=q 1.

·不断重复这样的操作,直到p>mid或q>R.将剩余还未加入B的元素以此加入B即可。

最后,将日序列复制回来。

·T(n)=2T(n/2) O(n)=O(nlogn)

Merge_sort(L,R): //伪代码 Mid=(L R)/2 Menge_sort(L,Mid),Merge _sort(Mid 1,R) p=L,q=Mid,pos=L While p <=Mid and q<=R do if A[p]<A[q] then B[pos ]=A[p ] else B[pos ]=A[q ] While p<=Mid do B[pos ]=A[p ] While q<=R do B[pos ]=A[q ] For i=L to R do A[i]=B[i]

快速排序

·在之前的分治中,我们总是将当前要解决的区间从中间等分成两半,两边分别解决,快速排序则运用了一种不同的分治方法。

-假设现在仍然要将区间[L.R]排序,我们在[u.R]内随机取一个值x,将所有小于A[x]的元素放在前面,否则放在后面。例如当前要将7,4,2,1,3,3排序,假设随机到x=5.A[x]=3.则数组变为2.1.3.3.7.4。

·假设有cnt个元素小于A[x].则递归地将[L,L cnt-1]以及[L cnt.R]排序。由于前面的元素一定小于后面的元素,递归完成之后数组即为有序。

在期望意义下,我们可以认为每次都会将区间分成长度相差不大的两段,因此快速排序的期望复杂度是O(nlogn)的。

Quick_sort(L,R)//伪代码 x=rand(L,R) p=L,q=R For i=L to R do if A[i]<A[x] then B[p ]-A[i] else B[q-]=A[i] For i=L to R doA[i]=B[i] Quick_sort(L,p-1),Quick_sort(q 1,R) -给出一个长度为n的序列A,输出将它从小到大排序之后的第k个元素的值。·1kn≤10^7

数据量有些难以接受。快速排序变形

Kth_element(L,R,k) if L==R then return A[L] x=rand(L,R) p=L,q=R For i=L to R do if A[i]<A[x] then B[p ]=A[i] else B[q--]=A[i] For i=L to R.do A[i]=B[i] if k<(p-L) then return Kth_element(L,p-1,k) else return Kth_element(q 1,R,k-(p-L)) ·给出一个序列长度为n的序列A,求A的逆序对个数。·若对于1<i<j<n,Ai>Aj.则称(i,j)是一对逆序对。n≤10^5,A≤10^9 (逆序对计数)

(数据结构)·枚举,我们需要统计有多少.满足i<j且Ai>Aj。

·将A离散化(即令Ai等于Ai在A序列中的从小到大的排名),从小到大地枚举j。令Bi表示有多少个x,满足Ax=i,且x<j。那么我们每次需要查询一段区间Bi的和,并将一个Bi加1。

·可以使用线段树或者树状数组维护,复杂度为O(nlogn)。

(归并排序)·事实上,我们只需要使用类似归并排序的分治就能解决这个问题。

·对于一段区间[L,R].我们需要将区间排好序,并返回这个区间内的逆序对个数。先令mid =(l r)/2,然后向两边递归,就计算出了所有满足L≤i<j≤mid,mid<i<j≤R的逆序对。现在只需要加上满足L≤i≤mid,mid<j≤R的逆序对。

·在将两边的序列合并的过程中,我们可以统计对于每个右边区间的数.在这个数加B序列时,有多少个左边区间内的数还未加入,也就是有多少左边区间的数比它大。将这个值加入答案即可。

·复杂度仍为O(nlogn)

有一个2^k×2^k的方格棋盘,恰有一个方格是黑色的,其他为白色。你的任务是用包含3个方格的L型牌覆盖所有白色方格。黑色方格不能被覆盖,且任意一个白色方格不能同时被两个或更多牌覆盖。如下图所示为L型牌的4种旋转方式。·k≤10 (棋盘覆盖问题)

·题目是要求用L型牌覆盖一个2k×2k的方格棋盘,棋盘有且只有一个黑色方格,此方格不能覆盖。

·考虑分治,将棋盘平均分为4块,每一块刚好是2^(k-1)x2^(k-1)的方格棋盘,但当前只有一块中含有一个黑色方格,所以要为另外三个方格构造出一个黑色方格,如下图所示:


未完待续,请关注我:学点干货。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved