2020.10.6 清北学堂 J2综合强化营 D6 分治笔记
分治
\(1\).定义
“分而治之”,即把大问题拆成一个个的小问题,然后分别解决这些小问题,最终求得答案。
\(2\).应用
\(\text{Example}\)
把一个长度 \(N\) 的数组从小到大排序
\(\text{Solution}\)
\(\text{Quick Sort}\ \to\) 分成两个小数组,保证左子数组例的数均小于右子数组,不断重复上述过程,完成排序
\(\text{Merge Sort}\ \to\) 分成两个较小的数组,对左子数组进行排序,对右子数组进行排序,最终合并成一个较大的数组,不断重复上述过程,完成排序
inline void quick_sort(int l,int r){
int mid=a[(l+r)>>1];
int i=l,j=r;
do{
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j){
swap(a[i],a[j]);
i++;j--;
}
}while(i<=j);
if(l<j) quick_sort(l,j);
if(i<r) quick_sort(i,r);
}
inline void merge_sort(int l,int r){
int mid=(l+r)>>1;
if(l==r) return;
merge_sort(l,mid);
merge_sort(mid+1,r);
int i=l,j=m+1,k=1;
while(i<=mid && j<=r){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
}
\(\text{Example 2}\)
一共有 \(n\) 片芯片,芯片有好有坏。我们不知道哪个是好芯片,哪个是坏芯片,但保证好芯片比坏芯片多
我们可以用两片芯片互相测试对方是否是好芯片。
已知好芯片一定能返回正确的结果,而坏芯片给出的结果是完全随机的。
我们现在希望能找到一个好芯片
\(\text{Solution 2}\)
分成两组,每组两个比较.
[好坏]或者[坏坏] \(\to\) 把两块芯片都去掉;
如果结果是[好好] \(\to\) 任选其中一块去掉.
剩下 \(1\) 个或 \(2\) 个 \(\to\) 是好芯片
奇数个 \(\to\) 任取一个和其它所有芯片比较,
如果有一半将此芯片判为好芯片 \(\to\) 好芯片
否则 \(\to\) 坏芯片 \(\to\) 去掉
\(\text{Problem 1}\) 求逆序对 \(\to\ \ \text{Merge Sort}\)
\(2\).二分算法
核心 : 把问题缩小为一个原规模 \(\dfrac{1}{2}\) 的子问题
常用 : 最小值最大 \(or\) 最大值最小 \(or\) 满足某条件的最值
\(\text{(1)}\) 二分查找
模板固定,不要混用。——来自 \(\text{lyd}\) 老师的忠告
\(\text{Problem}\ 1\)
原问题:一个长度为 \(N\) 的有序数组 \(A\) ,查询 \(x\) 是否在这 \(N\) 个数中
思路:
令 \(m\ =\ (l+r)\ >>1\)
按情况分类讨论:
- 若 \(A[m]\ ==\ x\),找到 \(x\) ,返回
- 若 \(A[m]\ >\ x\),故 \(A[m]\sim A[r]\) 中所有的数都大于 \(x\) ,二分查找 \((l, m)\)
- 若 \(A[m]\ <\ x\),故 \(A[l]\sim A[m]\) 中所有数都小于 \(x\) ,二分查找 \((m + 1, r)\)
inline bool Binary_Search(int x){ // [l,r)
int l=0,r=r-1,m;
while(l<=r){
if(A[m]==x) return true;
else if(A[m]<x) r=m-1;
else l=m+1;
}
return false;
}
\(\text{Problem 2}\)
给出 \(N\) 个月的开销,要求把 \(N\) 个月的开销按顺序划分成 \(M\) 个时间段,计算每一段的开销总和,求 \(M\) 个开销总和中最大值的最小值
\(\text{Solution 2}\)
求值问题 \(\to\) 判定问题
求值:求一个划分方式,(划分区间和的最小值)最小
判定 \((x)\):是否存在一个判定方式,它划分出的每一段区间的和的最大值 \(≤x\)
判定问题 \((x)\):是否存在一个判定方式,它划分出的每一个区间的和都 \(≤x\)
inline bool check(int x){
int cnt=0,len=0;
for(int i=1;i<=N;i++){
if(a[i]>x) return false;
if(len+a[i]>x){
len=a[i];
cnt++;
}
else{
len+=a[i];
}
}
return cnt<=M;
}

浙公网安备 33010602011771号