第二周总结

这是一个目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

这周学习的知识有
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宿主的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值