分治,分而治之;整天整夜的挂在嘴边....
其实就是将原问题分成n个规模较小而结构与原问题相似的子问题
然后递归地解决这些子问题,最后合并其结果就得到原问题大的解。
当n=2时的分治法又称二分法
分治——Divide and Conquer
因此Divide 和Conquer 是很重要的
分治一般分三个步骤:
1.分解(Divide):将原问题分成一系列子问题。
2.解决(Conquer):递归的解决个子问题。若子问题足够小,则可以直接求出
3.合并(combine):将子问题的结果合并成原问题的解
LIKE THIS:
分治的策略和解题思路:
if 问题不可分{
直接求出;
返回问题的解;
}
else{
对原问题进行分治;
递归对每一个分治部分求解;
归并整个问题,得出权问题的解;
}
在分治中较为重要的有快速幂
它是通过二进制与十进制的关系实现的,迭代式子:
(19)10=(10011)2
19=1*2^4+0*2^3+0*2^2+1*2^1+1*2^0
19=( ( ( ( ( (1)*2) +0) *2) +0) *2)+1)*2+1
B^19=B^16*B^2*B^1
B^19=((((((B)^2)^2)^2)*B^2)B
1 0 0 1 1
每次平方是必须的,但是只有对应2进制为1的时候,才乘B
我们的基本思路就变成把p转换为二进制,然后从二进制的最高位开始,如果当前二进制为1,那么乘B在平方,如果当前二进制位为0,只平方即可。结果就出来了。
*同余问题:*
(a+b+c) %k= ( (a+b)%k+c)%k
(a-b-c) %k= (a-b)%k -c
(a*b*c) %k =a*b %k *c %k
除此之外还有归并排序:
参考代码:
int cnt=0; // 逆序对个数
int a[100002], c[100002];
void worksort(int l,int r) //r=右边界索引; 归并排序!
{
int mid,tmp,i,j;
if(r>l+1)
{
mid=(l+r)/2; //中间边界
worksort(l,mid-1);
worksort(mid,r);
tmp=l;
for(i=l,j=mid;i<=mid-1 && j<=r;) //l r, mid 表示下标,并不是具体的值??
{
if(a[i]>a[j])
{
c[tmp++]=a[j++];
cnt+=mid-i; //排序找逆序对个数,
}
else
c[tmp++]=a[i++];
}
if(j<=r)
for(;j<=r;j++) c[tmp++]=a[j];
else
for(;i<=mid-1;i++) c[tmp++]=a[i];
for(i=l;i<=r;i++) a[i]=c[i];
}
else
{
if (l+1==r)
if (a[l]>a[r])
{
swap(a[l],a[r]);
cnt++;
}
}
}