二分三分矩阵快速幂 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.youkuaiyun.com/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;
}