红鲤鱼与绿鲤鱼与驴
今天学习 二分法 and 快速幂
二分查找函数:
在一个升序数组的 begin 和 end 前闭后开区间内进行二分查找
lower_bound (begin,end,val) 返回大于或等于val的第一个元素位置
upper_bound (begin,end,val) 返回大于val的第一个元素位置
如果所有元素都小于 val 则返回 end 的位置
补充:头文件:algorithm
如果要二分的是个小数 需要规定精度
double left,right,mid;
while(right - left > eps ){
mid = (right + left) / 2;
if( judge(mid) )
left = mid;
else
right = mid;
}
return mid;二分答案
二分枚举答案,由于进行二分,所以复杂度 log(n),比直接 for 的时间更短。
1、适用情况:求最值,可能答案区间有限且单调且大于零,检验答案合理性复杂度低
2、题目标志:最小值最大、最大值最小
3、模板代码:
while (l <= r){
int mid = (l + r) >> 1;//右移 效果相当于除以二
if (judge(mid)){
ans = mid;
l = mid + 1;
}else
r=mid - 1;
}
return ans ;4、例题1 SP297 AGGRCOW - Aggressive cows:
https://www.luogu.com.cn/problem/SP297
题意:有n个牛栏,分别位于X1,X2...Xn 选m个放进牛 使得相邻牛之间的最小距离值最大
思路:先对隔间编号从小到大排序,则最大距离不会超过两端的两头牛之间的差值,最小值为0。所以我们可以通过二分枚举最小值来求。假设当前的最小值为x,如果判断出最小差值为x时可以放下m头牛,说明当前的x有点小,就先让x变大再判断;如果放不下,说明当前的x太大了,就先让x变小然后再进行判断。直到求出一个最大的x就是最终的答案。
#include<iostream>
#include<algorithm>
using namespace std;
int n,c;
int a[100005];
int judge(int m){
int num=1,cnt=1;
for(int i=2;i<=n;i++){
if(a[i]-a[num]>=m){
cnt++;
num=i;
if(cnt==c)
return 1;
}
}
return 0;
}
int main() {
int t;
cin>>t;
while(t--){
cin>>n>>c;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
int l=1,r=a[n];
while(l<r){
int m=(l+r+1)/2;
if(judge(m))
l=m;
else
r=m-1;
}
cout<<l<<endl;
}
return 0;
}5、例题2 CF39H Multiplication Table:
https://www.luogu.com.cn/problem/CF448D
题意:有 n * m 乘法表,将 n * m 个数从小到大依次排列,第K个数是多少?
思路:由于数据既大且多,暴力构造乘法表然后排序的做法不可取。正确做法是使用二分查找。由于乘法表有个特殊的公式,即对于一个数X,X除以行数i 设得到的结果(整数表示)为Q,如果Q大于列数M,那么这个数就大于第i行所有的数,如果等于列数,说明这个数是第i行第Q大的数。如果小于列数,说明这个数比第i行前Q个数大。利用这一点查找mid在乘法表中所处的位置,然后判断mid与k的大小关系进而确定左右边界继续二分,直到找到该位置(左等于右)。
#include<iostream>
using namespace std;
int main()
{
long long n,m,k;
cin>>n>>m>>k;
long long l=1,r=n*m;
while(l<r){
long long mid=(l+r)/2,num=0;
for(long long i=1;i<=n;i++){
long long q=mid/i;
if(q>m)
num+=m;
else
num+=q;
}
if(num>=k)
r=mid;
else
l=mid+1;
}
cout<<l<<endl;
return 0;
}———————————————————— 分 界 线 ————————————————————
快速幂: ( a ^ b ) mod p
int power(int a,int b,int p){
int ans = 1 % p;
for(;b;b>>=1){
if( b & 1 )
ans=(long long)ans * a % p;
a=(long long)a * a % p;
}
return ans;
}矩阵快速幂:将快速幂中的底数变为矩阵 线性递推式
模板题:https://www.luogu.com.cn/problem/P3390
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int MAXN = 105;
struct Mat {
ll m[MAXN][MAXN];
}ans;
Mat Mul(Mat a, Mat b, ll n) {//计算矩阵a乘矩阵b,n为矩阵的大小
Mat c;
memset(c.m, 0, sizeof(c.m));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
c.m[i][j] = (c.m[i][j] + (a.m[i][k] * b.m[k][j]) % mod) % mod;
return c;
}
Mat Mul_power(Mat a, ll b, ll n) {//计算a^b,n为矩阵的大小
for (int i = 1; i <= n; i++)//构造单位矩阵
ans.m[i][i] = 1;
while (b) {
if (b & 1)
ans = Mul(ans, a, n);
a = Mul(a, a, n);
b >>= 1;
}
return ans;
}
int main() {
ll n;
ll k;
cin>>n>>k;
Mat zls;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>zls.m[i][j];
Mat zlss=Mul_power(zls,k,n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<<zlss.m[i][j]<<" ";
cout<<endl;
}
return 0;
}自言自语Part:
晚上有时间的话就把习题做了在发一篇 Day 1.5
Good Luck! 今天还算顺利

京公网安备 11010502036488号