基本算法模板


其他算法集合

二分

在哪边哪边等于mid(竖线),否则另外一侧变到点(要找的结果),减了要加

image-20220604181555503
int l=0,r=1e6;
while(l<=r)
{
	int mid = l+r >> 1;
	if(check()) r=mid; //
	else l=mid+1;
}
image-20220604182148814
int l=0,r=1e6;
while(l<=r)
{
	int mid = l+r+1 >> 1;
	if(check()) l=mid;
	else r=mid-1;
}

离散化

运用vector

vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());   // 去掉重复元素

// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于x的位置
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1; // 映射到1, 2, ...n
}

运用unordered_map

unordered_map<int, int> h;

int find(int x)
{
    if (h.count(x)) return h[x]; //如果存在返回离散化后的值
    return h[x] = cnt ++ ; //如果不存在将这个值离散化
}
         

高精度

加法

vector<int> add(vector<int> a,vector<int> b)
{
    vector<int> c;
    int t=0;
    for(int i=0;i<a.size()||i<b.size();i++)
    {
        if(i<a.size()) t+=a[i];
        if(i<b.size()) t+=b[i];
        c.push_back(t%10);
        t/=10;
    }
    if(t) c.push_back(t);
    return c;
    
}

减法

vector<int> sub(vector<int> a,vector<int> b) //a>b
{
	vector<int> c;
	int t=0;
	for(int i=0;i<a.size();i++)
	{
		t=a[i]-t; //a先减掉上回合剩余
		if(i<b.size()) t=t-b[i];
		c.push_back((t+10)%10) //t小于0时候要借位
		if(t<0) t=1;
		else t=0;
	}
	//去前导0
	if(c.size()>1 && c.back()==0 ) c.pop_back();
	return c;
}

乘法

vector<int> mul(vector<int> a,vector<int> b) //a大位b小位
{
	vector<int> c;
	int t=0;
    for(int i=0;i < a.size() || t;i++)
    {
        if(i<a.size()) t=a[i]*b+t;
        c.push_back(t%10);
        t/=10;
    }
    if(c.size()>1 && c.back()==0) c.pop_back();
    return c;
}

除法

vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    //高位到低位
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

前缀和

一维

int a[N],s[N];//s[i]前缀和数组

	for(int i=1;i<=n;i++) 
    {
        cin >> a[i];
        s[i]=a[i]+s[i-1];
    }
    
    cout <<s[r]-s[l-1];//区间l到r的和

二维

image-20220604170854738
for(int i=1;i<=n;i++)
{
		for(int j=1;j<=m;j++)
		{
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
		}
}
cout << s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];//小-1,奇-偶+

差分

维护多次对序列的一个区间加上一个数,并在最后询问某一位的数或是多次询问某一位的数。注意修改操作一定要在查询操作之前。

一维

int a[N],b[N];

	for(int i=1;i<=n;i++) cin >> a[i]
	for(int i=1;i<=n;i++) b[i]=a[i]-a[i-1]; //b为差分数组
	//在[l,r]区间每个数加上c
	b[l]+=c;
	b[r+1]-=c;
	//求一遍前缀和
	for(int i=1;i<=n;i++) a[i]=a[i-1]+b[i];
	

二维

int a[N][N],b[N][N];
void Insert(int x1,int y1,int x2,int y2,ll e)
{
    //大+1,奇-偶+
	b[x1][y1]+=e;
	b[x2+1][y1]-=e; 
	b[x1][y2+1]-=e;
	b[x2+1][y2+1]+=e;
}

	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin >> a[i][j]
	//构造b数组相当于在[i,j]到[i,j]位置上插入a[i][j]
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			Insert(i,j,i,j,a[i][j]);
	//在[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]+b[i][j];

l o w b i t lowbit lowbit

int lowbit(int x){
    return x & -x;
}

区间问题

判断两个区间是否相交

//思路就是如果两个区间不相交,那么最大的开始端一定大于最小的结束端
//(点重合算重合的话带等号)
if(max(a1, a2) < min(b1, b2))//有交集
else //无交集

有交集的区间合并

void merge(vector<PII> &segs)
{
    vector<PII> res;
	//按照起始点排序
    sort(segs.begin(), segs.end());
	//都置为最小
    int st = -2e9, ed = -2e9;//表示正在合并的端点 
    //ed取最小为了保证第一个区间被操作
    for (auto seg : segs)
        if (ed < seg.first) //区间不相交
        {
            //st最小表示还没开始操作
            if (st != -2e9) res.push_back({st, ed});
            //新开一个区间
            st = seg.first, ed = seg.second;
        }
        else ed = max(ed, seg.second);
	//把最后一个区间放进去
    if (st != -2e9) res.push_back({st, ed});

    segs = res;
}

向上取整

//a/b(a>0 b>0)
(a+b-1)/b
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值