文章目录
其他算法集合
二分
在哪边哪边等于mid(竖线),否则另外一侧变到点(要找的结果),减了要加
int l=0,r=1e6;
while(l<=r)
{
int mid = l+r >> 1;
if(check()) r=mid; //
else l=mid+1;
}
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的和
二维
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