这是一个目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这周学习的知识有
1栈、队列、串和stack、queue
2二分
3前缀和与差分
4位运算
其中1和4掌握的不是很好
该博客记录这周写的一些关于以上知识点的题目
一、二分
二分分为实数二分和整数二分
二分算法就三个模板 整数两个
整数二分模板
#include<iostream>
using namespace std;
#define N 10010
int a[N],n,x;
void moban1(int a[N],int x)//二分模板1 不用考虑边界问题
{
int l=0,r=n-1;
while(l<r)
{
int mid=(l+r)/2;//不断更新中间值
if(a[mid]>=x)//如果中间值大于要寻找的数
r=mid;//更新右边界
else
l=mid+1;
}
if(a[l]==x)
cout<<"寻找成功且该数的下标为 "<<l;
else
cout<<"-1";
}
//如果数组为2 2 2 3 如果寻找2那么模板1只会找到第一次出现的下标
void moban2(int a[N],int x)
{
int l=0,r=n-1;
while(l<r)
{
int mid=(l+r+1)/2;//防止进入死循环,因为mid的值是向下取整
if(a[mid]<=x)
l=mid;
else
r=mid-1;
}
if(a[l]==x)
cout<<"寻找成功且该数的下标为 "<<l;
else
cout<<"-1";
}
//如果数组为2 2 2 3 如果寻找2那么模板2只会找到最后一次出现的下标
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
cin>>x;
moban1(a,x);
cout<<endl;
moban2(a,x);
return 0;
}
如果输入一个长度为6的有序数组 2 2 2 3 3 4 中找到2的为值则
6
2 2 2 3 3 4
2
寻找成功且该数的下标为 0
寻找成功且该数的下标为 2
实数二分
实数二分比较简单就一个模板 与整数二分不同的是要考虑精度问题
ps:实数之间不能直接用==来判断相等 都是可以用一个特别小的数来表示两者接近
Q;任意给一个实数(范围0到10000)求其的立方根 结果保留3位数字
#include<iostream>
#include<cstdio>
double x;
using namespace std;
int main()
{
cin>>x;
double l=0,r=10000;
while(r-l>1e-5)//le(-n),n=报留的数字加二
{
double mid=(l+r)/2;
if(mid*mid*mid>=x)
r=mid;
else
l=mid;
}
printf("%.3lf的立方根是%.3lf",x,l);
}
样例:
100
100.000的立方根是4.642
实际写题时要学会将模板套进去
二、前缀和与差分
一维前缀和
练习:
给出一个长度为n的数组,输入m次查询每次输入一个l和r,求出[l,r]之间所有数之和;
代码如下(示例):
#include<iostream>
using namespace std;
#define N 10001
int n,m;
int a[N],s[N];//s[N]储存前n项和
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)//下标从1开始方便之后使用
{
cin>>a[i];
s[i]=s[i-1]+a[i];//构造前n项和
}
while(m--)
{
int l,r;
cin>>l>>r;
cout<<s[r]-s[l-1]<<endl;
}
}
5 2
1 2 3 4 5
1 3
6
2 4
9
--------------------------------
Process exited after 17.55 seconds with return value 0
请按任意键继续. . .
二维前缀和
同一维前缀和一样,我们先来定义一个二维数组s[][], s[i][j]表示二维数组中,左上角(1,1)到右下角( i,j )所包围的矩阵元素的和。
二维前缀和的公式是s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
则二维前缀和有
问题:输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
代码如下
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1010;
int a[N][N],s[N][N];
int main()
{
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];//与一维差分一样储存数据
}
while(q--)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
cout<<s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]<<endl;
}
return 0;
}
输入
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
输出
17
27
21
一维差分
差分如同前缀和的逆运算,要构造差分数组
差分数组:
首先给定一个原数组a:a[1], a[2], a[3], a[n];
然后我们构造一个数组b : b[1] ,b[2] , b[3], b[i];
使得 a[i] = b[1] + b[2 ]+ b[3] +, + b[i]
如果想让上式成立则要有
a[0 ]= 0;
b[1] = a[1] - a[0];
b[2] = a[2] - a[1];
b[3] =a [3] - a[2];
…
b[n] = a[n] - a[n-1];
这样就可以利用差分解决类似这样的问题;给定区间[l ,r ],让我们把a数组中的[ l, r]区间中的每一个数都加上c
Q:输入一个长度为n的整数序列。
接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。
请你输出进行完所有操作后的序列。
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]-a[i-1]; //构建差分数组
}
int l,r,c;
while(m--)
{
cin>>l>>r>>c;
b[l]+=c; //表示将序列中[l, r]之间的每个数加上c
b[r+1]-=c;
}
for(int i=1;i<=n;i++)
{
b[i]+=b[i-1]; //求前缀和运算
//等价于啊a[i]=a[i-1]+b[i];
cout<<b[i]<<" ";
//等价于cout<<a[i]<<" ";
}
return 0;
}
5 3
1 2 3 4 4
1 2 1
1 5 1
1 4 -2
1 2 2 3 5
--------------------------------
Process exited after 23.9 seconds with return value 0
请按任意键继续. . .
二维差分
如果扩展到二维,我们需要让二维数组被选中的子矩阵中的每个元素的值加上c
可以构造差分数组b
b[x1][y1] + = c;
b[x1,][y2+1] - = c;
b[x2+1][y1] - = c;
b[x2+1][y2+1] + = c;
每次对b数组执行以上操作,等价于:
for(int i=x1;i<=x2;i++)
for(int j=y1;j<=y2;j++)
a[i][j]+=c;
可以借助图像去理解
b[x1][ y1 ] +=c ; 对应图1 ,让整个a数组中蓝色矩形面积的元素都加上了c。
b[x1,][y2+1]-=c ; 对应图2 ,让整个a数组中绿色矩形面积的元素再减去c,使其内元素不发生改变。
b[x2+1][y1]- =c ; 对应图3 ,让整个a数组中紫色矩形面积的元素再减去c,使其内元素不发生改变。
b[x2+1][y2+1]+=c; 对应图4,让整个a数组中红色矩形面积的元素再加上c,红色内的相当于被减了两次,再加上一次c,才能使其恢复。
可以将构造差分数组和得出结果写出一个函数
void insert(int x1,int y1,int x2,int y2,int c)
{ //对b数组执行插入操作,等价于对a数组中的(x1,y1)到(x2,y2)之间的元素都加上了c
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
//在构造b数组时参数为insert(i,j,i,j,a[i][j]);
二维差分思路
题目练习: AcWing 798. 差分矩阵
输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数x1, y1, x2, y2, c,其中(x1, y1)和(x2, y2)表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上c。
请你将进行完所有操作后的矩阵输出。
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e3+10;
int a[N][N],b[N][N];
void insert(int x1,int y1,int x2,int y2,int c)
{
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
int main()
{
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
insert(i,j,i,j,a[i][j]); //¹¹½¨²î·ÖÊý×é
}
while(q--)
{
int x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
insert(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
cout<<b[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
输入样例:
3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1
输出样例:
2 3 4 1
4 3 4 1
2 2 2 2
三.位运算
& 按位与 :1&1=1 1&0=0
6的二进制是110,11的二进制是1011,那么6 & 11的结果就是2
| 按位或 :1|0=1,0|0=0
^ 按位异或 相同为0不同为1
~ 按位取反
<< 左移(左边消失,右边补0)
(>>)右移(右边消失,左边补符号位)
总结
就总结到这吧 kmp的next宿主的