给出一串数以及一个数字C,要求计算出所有A - B = C 的数对的个数(不同位置的数字一样的数对算不同的数对)。原题
借鉴的思路
这个思路的核心就是将A - B = C转换位A - C = B。
1、在输入的时候使用map来统计每个数出现的次数。
2、通过将每一个数都减去C来将A转换成B,如此,只需要统计符合要求的B的次数就可以得到这个题目的答案。
3、对map进行一次遍历,得到所有符合要求的B的出现次数的累加和,即为正确答案。原因:1中统计的是一长串数中每个数字出现的频率,如果没有在这里出现的数字其频率自然为0,在2中将每个A所要求的B求出来,并将它的值直接赋给A,于是就可以拿着这个想要查找到的目标数组去map表里查,最终就很容易得到了符合要求的B的个数。
1 | #include<iostream> |
经验教训
map真的好好用
又一个可以使用map的题
原题太长了,就不贴了,思路很简单,就是对于每一次存放操作,建立一次二维映射;对于每一次查询操作,直接输出其映射的值。
解法
1 | #include<iostream> |
unique
1、作用:去重
2、用法:unique(数组名,数组名+大小),与sort一模一样
3、注意:
在unique之前必须保证去重数组有序,也就是得sort一下。
unique并不会生成一个新的数组,而是将原数组多余的部分”移“到了数组之后,同时unique本身还会返回一个指针,指向去重之后的最后一位。
利用C++可以指针相加减的特点,我们可以通过unique-数组指针来知道去重之后数组的”大小“。
1 | int size = unique(x,x+k)-x; |
真的很好用,在用set超时的情况下可以考虑一下噢。
二维变长数组
下列语句申请了100个vector,实现了二维变长数组
1 | vector<int>vec[100] |
在map中使用两个索引对应一个value
方法一:
1 | map<pair<int,int>,int>ma; |
方法二:(摘自又一个可以使用map的题)
1 | map<int,map<int,int> > m; |
通过value确定数组的index
lower_bound(起始地址,结束地址,要查找的数值)-起始地址;
上述的结果就是index
使用sort
方法一:重写sort的比较函数
方法二:重载结构体的大于号
BFS和DFS
DFS
1、使用DFS搜索方案时要记得回退(就是把标记已经走过的点取消标记)—回溯法。
2、DFS的特点是搜索到下一个可访问节点立即就去访问下一个节点(只修改当前访问点的标记,不修改下一个节点的标记)
3、求最短距离要在DFS函数中多加一个参数记录步数,最后在递归终点取最小值就可以。
4、DFS有可能会被卡,沿着一条路走到TLE。
BFS
1、BFS的特点是搜索到下一个可访问节点就将它加入到队列中,而不是立即去访问它,首先要遍历当前节点所有可以访问的节点。(会修改下一个可访问节点的标记,为的是避免在以后的搜索中不再重复将这个待访问点加入到队列中)
2、BFS可以天然的求出最小路径。因为BFS是一层一层地向外扩展,每一个点最先被加入到队列时,一定是通过拓展层数最小地方法扩展到的。(也就是第一个求出来的结果一定是最短的)
3、BFS更占空间,更难写。
1 | void bfs() |
相同点
1、无论BFS还是DFS,我们都有一个提供这些信息的东西。
2、这些信息定义了一个子问题,提供了定位一个子问题所需的所有条件,定义了解决一个问题过程中的状态。
3、都要对结果进行判重,防止重复搜索甚至陷入死循环。
取模
1、同余符号=(就那个恒等于符号)
就是等号两边取模结果相同
2、模意义下的 +-/
%8的域里面
(6/3)%8 = 2;
(63)%8 = 2;
1 2
1 -
2在模八意义下的逆元不存在:2x%8 = 1无解
筛素数
1、欧拉筛:去掉当前数的所有质数。
2、优化:只用质素去筛,在筛之前判断是不是质数。
3、因为每个数可能会有不止一个的质因子,因此理想的状态是使用最小质因子来筛。
4、也就是需要多一个break条件
当前数%质数数组[index] == 0 满足这个条件就break;
二重循环,外层是当前数,内层是质数数组的index循环。
最小公约数
1、核心代码
if(a>b)
gcd(a,b) = gcd(a%b,b);
2、在alg这个头文件里有个自带的_gcd函数
3、最大公约数*最小公倍数 = 两个数的乘积
4、丢番图方程
ax + by = c;
丢番图方程(扩展欧几里得)
1、判断什么方程有解
当且仅当gcd(a,b)|c时有解(|表示整除)
如果ax+by = 5,那么ax+by = 10也一定有解
2、ax+by = gcd(a,b)一定有解 即必须c%gcd(a,b) = 0
如果gcd = 1那么这个方程一定有解
3、
5在11域中的逆元
5x + 11y = gcd(5,11);
phi
比如求phi 10
1、筛去质因子(2,5)
2、筛去质因子的倍数
3、减去筛去的数(奇数加,偶数减)
4、加上多减的,减去多加的
梦比乌斯函数mub
mub就是容斥时的系数
id*mub = phi(这是个卷积)
Sparse Table Algorithm
1、f[i][j]表示的是从i开始,区间长度为2^j的最小值,也就是[i,i+2^j-1]的最小值。
2、求[2,8]的最小值分成[2,5][5,8]两个区间的最小值。其中,k = floor(log(b-a+1)/log(2)),即2^k = b-a+1。
3、f[i][0] 区间长度为1,结果是它本身。
树状数组
1、高效的获取连续k个数的和。
2、给定序列(数列)A,我们设一个数组C满足C[i] = 。k是二进制末尾0的个数,i从1开始。
3、lowbit = i&(-i);
4、A[1]+A[2]+…+A[6] = C[6]+C[4];
前驱的编号即为比自己小的,最近的,最末连续0比自己多的数。
t = x-lowbit(x);//前驱的编号,相当于x减去了最右边的1
5、求区间[x,y]之和getsum(y)-getsum(x-1);
6、修改某个A[i],就需改动所有包含A[i]的C[j];就是要修改从叶子节点到根节点路径上的所有C[j]。
父结点:比自己大的,最近的,末位连续0比自己多的
T = x+lowbit(x);//x父结点的编号相当于让x最右边的1变为0,增加1个0
7、如果整数范围是1e9,显然不能开那么大的数组,于是我们对它们进行排序,然后按照1~numberofdata这样子赋给它们下标,只需要知道它们大相对大小关系即可,不需要知道它们具体是多少。
树上倍增
1、fa[v][k] = fa[fa[v][k-1]][k-1];
2、从低位到高位枚举,将向上查找的层数分成一个1后面好多个0这种形式。
101&001 = 1;
101&010 = 0;
101&100 = 100 = 1;
3、求公共祖先
-先让层数较多的那个节点向上跳到另一个节点的同层。
-然后逐个去试,从根节点(最高层)向下跳,知道此时两个节点的祖先不相同结束,则表示上一步就是所求的最近公共祖先。
时间复杂度
O :
对任意的N,存在n>N,使得f(n)<=Cg(n),则我们得到f(n) = O(g(n))。O是时间增长的上界。
Ω:
对任意的N,存在n>N,使得f(n)>=Cg(n),则我们得到f(n) = Ω(g(n))。O是时间增长的下界。
θ:
对任意的N,存在n>N,使得C1g(n)<=f(n)<=C2g(n),则f(n) = θ(g(n))。
若f(n) = O(g(n)),f(n) = Ω(g(n)),则(n) = θ(g(n))。
一个有用的STL函数
prev_permutation函数可以制造前一个排列,如果已经为第一个,则返回false
1 | #include<bits/stdc++.h> |
高精
1 | void jiafa(int k)//高精加法 |