二分三分矩阵快速幂

二分三分矩阵快速幂 2020.2.17

二分法

lower_bound upper_bound(begin,end,val)
返回指针

解决问题

具有单调性/连续性的问题二分查找
最大最小问题/最小最大问题二分答案

小数
规定精度

double l,r,mid;
while(right - left > eps)1e-8
	mid = (right + left)/2;
	if(judge(mid)) left = mid;
	else right = mid;
return mid;

二分答案
使用情况:求最值,可能答案区间有限且单调,检验答案合理性复杂度低。
Ex 如果一个数列中2*K 的元素中前K个元素与后K个元素和都不大与S,那么我们说这些元素是有趣的。
给定S,给你一个长度为N的数列,求各个元素从本身开始能构成的最长有趣元素的长度。
所有元素均为正数
并不能从起点二分,要从起点/终点二分

while(l<=r)
{
	int mid = (l+r)>>1;
	if(judge(mid))
	{
		and = mid;
		l = mid+1;
	}
	else r = mid -1;
}
return ans;

Ex 有n个牛栏,分别位于X1,X2…Xn 选m个放进牛栏,使得相邻牛之间的最小距离值最大 ( 二分最小距离值)
https://blog.csdn.net/weixin_42105529/article/details/81231393
Ex 有nm乘法表,将nm个数从小到大依次排列,第K个数是多少

三分法 凸性函数

以求最大值为例
对比f(lmid)与f(rmid)
若f(lmid)<f(rmid)
那么区间变为lmid~r
否则变为l~rmid

快速幂

求 a^b mod p

a^(2i) = a^i  *  a^i
快速求出a^2 ^4 ^8.......
将b做二进制拆分
int quickpow(int a, int p ,int mod)
{
	int ans = 1//!!!!!
	int a = a%mod;
	while(p)
	{
		if(p&1) //p  odd
			ans = (ans*a)%mod;  //奇数乘一次 偶数直接翻倍a
		p>>=1;
		a=(a*a)%mod;
	}
	return ans;
}

矩阵快速幂

将快速幂中的底数变为矩阵
优势:线性递推式
Ex 斐波那契数列
求斐波那契数列的第n项
n<=1e18

1 1    *   F(i-1)    =   F(i)
1 0        F(i-2)        F(i-1)
Fn    =    1  1  ^ (n-1)     *    F1
Fn-1       1  0                   F0
#include <stdio.h>
#include <iostream>
#include<string.h>
using namespace std;
struct node {
	int mat[2][2];
}; 
int mod = 10000;
int len=2;
struct node mul(struct node x,struct node y){ 
	struct node tmp;
	for(int i=0;i<len;i++){
		for(int j=0;j<len;j++){
			tmp.mat[i][j]=0;
			for(int k=0;k<len;k++){
				tmp.mat[i][j]+=(x.mat[i][k]*y.mat[k][j])%mod;
			}
			tmp.mat[i][j]=tmp.mat[i][j]%mod;
		}
	}
	return tmp;
} 
struct node matpow(struct node x,struct node y,int num){ 
	while(num){
		if(num&1){
			y=mul(y,x);
		}
		x=mul(x,x);
		num=num>>1;
	}
	return y;
} 
char res[2][2];
int main()
{
    int N;
    while(scanf("%d",&N),N!=-1)
    {
        struct node a,b,res;
        a.mat[0][0]=1;a.mat[0][1]=1;a.mat[1][0]=1;a.mat[1][1]=0;
        b.mat[0][0]=1;b.mat[0][1]=1;b.mat[1][0]=1;b.mat[1][1]=0;
        if(N==0)
        {
            printf("0\n");
            continue;
        }
        if(N==1)
        {
            printf("1\n");
            continue;
        }
        else
        {
            res=matpow(a,b,N-2);
            printf("%d\n",res.mat[0][0]); 
        }
          
    }
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Leo9344/article/details/104352606
今日推荐