vector<int>add(vector<int>&A, vector<int>&B)// C = A + B, A >= 0, B >= 0{if(A.size()< B.size())returnadd(B, A);
vector<int> C;int t =0;for(int i =0; i < A.size(); i ++){
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)// C = A - B, 满足A >= B, A >= 0, B >= 0{
vector<int> C;for(int i =0, t =0; i < A.size(); i ++){
t = A[i]- t;if(i < B.size()) t -= B[i];
C.push_back((t +10)%10);if(t <0) t =1;else t =0;}while(C.size()>1&& C.back()==0) C.pop_back();return C;}
高精度乘低精度
vector<int>mul(vector<int>&A,int b)// C = A * b, A >= 0, b >= 0{
vector<int> C;int t =0;for(int i =0; i < A.size()|| t; i ++){if(i < A.size()) t += A[i]* b;
C.push_back(t %10);
t /=10;}while(C.size()>1&& C.back()==0) C.pop_back();return C;}
高精度除以低精度
vector<int>div(vector<int>&A,int b,int&r)// A / b = C ... r, A >= 0, b > 0{
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;}
树状数组
intlowbit(int x)// 返回末尾的1{return x &-x;}voidupdate(int x,int c)// 位置x加c{for(int i = x; i <= n; i +=lowbit(i)) tr[i]+= c;}intquery(int x)// 返回前x个数的和{int res =0;for(int i = x; i; i -=lowbit(i)) res += tr[i];return res;}
马拉车算法
voidinit()// a[]为原串,b[]为插入'#'后的新串{int k =0;
b[k ++]='$', b[k ++]='#';for(int i =0; i < n; i ++) b[k ++]= a[i], b[k ++]='#';
b[k ++]='^';
n = k;}voidmanacher()// 马拉车算法,b[]为插入'#'后的新串{int mr =0, mid;for(int i =1; i < n; i ++){if(i < mr) p[i]=min(p[mid *2- i], mr - i);else p[i]=1;while(b[i - p[i]]== b[i + p[i]]) p[i]++;if(i + p[i]> mr){
mr = i + p[i];
mid = i;}}}
voidinsert(char str[])// 将str插入Trie中{int p =0;for(int i =0; str[i]; i ++){int u = str[i]-'a';if(!tr[p][u]) tr[p][u]=++ idx;
p = tr[p][u];}
cnt[p]++;// 记录单词出现次数}voidbuild()// 创建AC自动机{int hh =0, tt =-1;for(int i =0; i <26; i ++)if(tr[0][i])
q[++ tt]= tr[0][i];while(hh <= tt){int t = q[hh ++];for(int i =0; i <26; i ++){int p = tr[t][i];if(!p) tr[t][i]= tr[ne[t]][i];else{
ne[p]= tr[ne[t]][i];
cnt[p]+= cnt[ne[p]];
q[++ tt]= p;}}}}
struct Node
{int s[2], p, v;int size;voidinit(int _v,int _p){
v = _v, p = _p;
size =1;}}tr[N];int root, idx;voidpushup(int x){// TODO: 利用子节点信息维护当前节点信息}voidpushdown(int x){// TODO: 将懒标记下传}voidrotate(int x)// 旋转{int y = tr[x].p, z = tr[y].p;int k = tr[y].s[1]== x;
tr[z].s[tr[z].s[1]== y]= x, tr[x].p = z;
tr[y].s[k]= tr[x].s[k ^1], tr[tr[x].s[k ^1]].p = y;
tr[x].s[k ^1]= y, tr[y].p = x;pushup(y),pushup(x);}voidsplay(int x,int k)// splay操作{while(tr[x].p != k){int y = tr[x].p, z = tr[y].p;if(z != k)if((tr[y].s[1]== x)^(tr[z].s[1]== y))rotate(x);elserotate(y);rotate(x);}if(!k) root = x;}
dijkstra
int h[N], e[M], w[M], ne[M], idx;int dist[N];bool st[N];intdijkstra()// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1{memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0,1});while(heap.size()){auto t = heap.top();
heap.pop();int ver = t.second, distance = t.first;if(st[ver])continue;
st[ver]=true;for(int i = h[ver]; i !=-1; i = ne[i]){int j = e[i];if(dist[j]> dist[ver]+ w[i]){
dist[j]= dist[ver]+ w[i];
heap.push({dist[j], j});}}}if(dist[n]==0x3f3f3f3f)return-1;return dist[n];}
dijkstra
voiddijkstra()// 求1号点到n号点的最短路距离{memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0,1});while(heap.size()){auto t = heap.top();
heap.pop();int ver = t.second, distance = t.first;if(st[ver])continue;
st[ver]=true;for(int i = h[ver]; i !=-1; i = ne[i]){int j = e[i];if(dist[j]> dist[ver]+ w[i]){
dist[j]= dist[ver]+ w[i];
heap.push({dist[j], j});}}}}
拓扑排序
voidtopsort(){int hh =0, tt =-1;// d[i] 存储点i的入度for(int i =1; i <= n; i ++)if(!d[i])
q[++ tt]= i;while(hh <= tt){int t = q[hh ++];for(int i = h[t]; i !=-1; i = ne[i]){int j = e[i];if(-- d[j]==0)
q[++ tt]= j;}}}
快速幂
intqmi(int a,int k,int p)// 求a^k mod p{int res =1% p;while(k){if(k &1) res =(LL)res * a % p;
a =(LL)a * a % p;
k >>=1;}return res;}
判定质数
boolis_prime(int x){if(x <2)returnfalse;for(int i =2; i <= x / i; i ++)if(x % i ==0)returnfalse;returntrue;}
线性筛质数
voidget_primes(int n){for(int i =2; i <= n; i ++){if(!st[i]) primes[cnt ++]= i;for(int j =0; primes[j]<= n / i; j ++){
st[primes[j]* i]=true;if(i % primes[j]==0)break;}}}
欧几里得算法
intgcd(int a,int b){return b ?gcd(b, a % b): a;}
扩展欧几里得算法
intexgcd(int a,int b,int&x,int&y)//求x, y,使得ax + by = gcd(a, b){if(!b){
x =1; y =0;return a;}int d =exgcd(b, a % b, y, x);
y -=(a / b)* x;return d;}
卢卡斯定理
intqmi(int a,int k,int p)// 快速幂模板{int res =1% p;while(k){if(k &1) res =(LL)res * a % p;
a =(LL)a * a % p;
k >>=1;}return res;}intC(int a,int b,int p)// 通过定理求组合数C(a, b){if(a < b)return0;
LL x =1, y =1;// x是分子,y是分母for(int i = a, j =1; j <= b; i --, j ++){
x =(LL)x * i % p;
y =(LL) y * j % p;}return x *(LL)qmi(y, p -2, p)% p;}intlucas(LL a, LL b,int p){if(a < p && b < p)returnC(a, b, p);return(LL)C(a % p, b % p, p)*lucas(a / p, b / p, p)% p;}
高斯消元
intgauss()// 高斯消元,答案存于a[i][n]中,0 <= i < n{int c, r;for(c =0, r =0; c < n; c ++){int t = r;for(int i = r; i < n; i ++)// 找绝对值最大的行if(fabs(a[i][c])>fabs(a[t][c]))
t = i;if(fabs(a[t][c])< eps)continue;for(int i = c; i <= n; i ++)swap(a[t][i], a[r][i]);// 将绝对值最大的行换到最顶端for(int i = n; i >= c; i --) a[r][i]/= a[r][c];// 将当前行的首位变成1for(int i = r +1; i < n; i ++)// 用当前行将下面所有的列消成0if(fabs(a[i][c])> eps)for(int j = n; j >= c; j --)
a[i][j]-= a[r][j]* a[i][c];
r ++;}if(r < n){for(int i = r; i < n; i ++)if(fabs(a[i][n])> eps)return2;// 无解return1;// 有无穷多组解}for(int i = n -1; i >=0; i --)for(int j = i +1; j < n; j ++)
a[i][n]-= a[i][j]* a[j][n];return0;// 有唯一解}intgauss()// 高斯消元,答案存于a[i][n]中,0 <= i < n{int c, r;for(c =0, r =0; c < n; c ++){int t = r;for(int i = r; i < n; i ++)// 找非零行if(a[i][c])
t = i;if(!a[t][c])continue;for(int i = c; i <= n; i ++)swap(a[r][i], a[t][i]);// 将非零行换到最顶端for(int i = r +1; i < n; i ++)// 用当前行将下面所有的列消成0if(a[i][c])for(int j = n; j >= c; j --)
a[i][j]^= a[r][j];
r ++;}if(r < n){for(int i = r; i < n; i ++)if(a[i][n])return2;// 无解return1;// 有多组解}for(int i = n -1; i >=0; i --)for(int j = i +1; j < n; j ++)
a[i][n]^= a[i][j]* a[j][n];return0;// 有唯一解}voidgauss()// 高斯消元,答案存于a[i][n]中,0 <= i < n{int c, r;for(c =0, r =0; c < n; c ++){int t = r;for(int i = r; i < n; i ++)// 找绝对值最大的行if(fabs(a[i][c])>fabs(a[t][c]))
t = i;if(fabs(a[t][c])< eps)continue;for(int i = c; i <= n; i ++)swap(a[t][i], a[r][i]);// 将绝对值最大的行换到最顶端for(int i = n; i >= c; i --) a[r][i]/= a[r][c];// 将当前行的首位变成1for(int i = r +1; i < n; i ++)// 用当前行将下面所有的列消成0if(fabs(a[i][c])> eps)for(int j = n; j >= c; j --)
a[i][j]-= a[r][j]* a[i][c];
r ++;}if(r < n){for(int i = r; i < n; i ++)if(fabs(a[i][n])> eps)return2;// 无解return1;// 有无穷多组解}for(int i = n -1; i >=0; i --)for(int j = i +1; j < n; j ++)
a[i][n]-= a[i][j]* a[j][n];return0;// 有唯一解}voidgauss()// 高斯消元,答案存于a[i][n]中,0 <= i < n{int c, r;for(c =0, r =0; c < n; c ++){int t = r;for(int i = r; i < n; i ++)// 找非零行if(a[i][c])
t = i;if(!a[t][c])continue;for(int i = c; i <= n; i ++)swap(a[r][i], a[t][i]);// 将非零行换到最顶端for(int i = r +1; i < n; i ++)// 用当前行将下面所有的列消成0if(a[i][c])for(int j = n; j >= c; j --)
a[i][j]^= a[r][j];
r ++;}if(r < n){for(int i = r; i < n; i ++)if(a[i][n])return2;// 无解return1;// 有多组解}for(int i = n -1; i >=0; i --)for(int j = i +1; j < n; j ++)
a[i][n]^= a[i][j]* a[j][n];return0;// 有唯一解}
快速傅里叶变换
struct Complex
{double x, y;
Complex operator+(const Complex& t)const{return{x + t.x, y + t.y};}
Complex operator-(const Complex& t)const{return{x - t.x, y - t.y};}
Complex operator*(const Complex& t)const{return{x * t.x - y * t.y, x * t.y + y * t.x};}};int rev[N], bit, tot;// tot = 1 << bitvoidfft(Complex a[],int inv){for(int i =0; i < tot; i ++)
rev[i]=(rev[i >>1]>>1)|((i &1)<<(bit -1));for(int i =0; i < tot; i ++)if(i < rev[i])swap(a[i], a[rev[i]]);for(int mid =1; mid < tot; mid <<=1){auto w1 =Complex({cos(PI / mid), inv *sin(PI / mid)});for(int i =0; i < tot; i += mid *2){auto wk =Complex({1,0});for(int j =0; j < mid; j ++, wk = wk * w1){auto x = a[i + j], y = wk * a[i + j + mid];
a[i + j]= x + y, a[i + j + mid]= x - y;}}}}
大步小步算法
intbsgs(int a,int b,int p)// a ^ x ≡ b (mod p) 的最小非负整数解{if(b ==1)return0;int k =sqrt(p)+1;
unordered_map<int,int> hash;for(int i =0, j = b; i < k; i ++){
hash[j]= i;
j =(LL)j * a % p;}int ak =1;for(int i =0; i < k; i ++) ak =(LL)ak * a % p;for(int i =1, j = ak; i <= k; i ++){if(hash.count(j)&&(LL)i * k >= hash[j])return(LL)i * k - hash[j];
j =(LL)j * ak % p;}return-1;}
Andrew算法
int stk[N], top;
PDD q[N];bool used[N];
PDD operator-(PDD a, PDD b)// 向量减法{return{a.x - b.x, a.y - b.y};}doubleoperator*(PDD a, PDD b)// 叉积、外积{return a.x * b.y - a.y * b.x;}doubleoperator&(PDD a, PDD b)// 内积、点积{return a.x * b.x + a.y * b.y;}doublearea(PDD a, PDD b, PDD c)// 以a, b, c为顶点的有向三角形面积{return(b - a)*(c - a);}doubleget_len(PDD a)// 求向量长度{returnsqrt(a & a);}doubleget_dist(PDD a, PDD b)// 求两个点之间的距离{returnget_len(b - a);}voidandrew()// Andrew算法, 凸包节点编号逆时针存于stk中,下标从0开始{sort(q, q + n);for(int i =0; i < n; i ++){while(top >=2&&area(q[stk[top -2]], q[stk[top -1]], q[i])<=0){if(area(q[stk[top -2]], q[stk[top -1]], q[i])<0)
used[stk[-- top]]=false;else
top --;}
stk[top ++]= i;
used[i]=true;}
used[0]=false;for(int i = n -1; i >=0; i --){if(used[i])continue;while(top >=2&&area(q[stk[top -2]], q[stk[top -1]], q[i])<=0)
top --;
stk[top ++]= i;}
top --;// 起点重复添加了一次,将其去掉}
欧拉函数
intphi(int x){int res = x;for(int i =2; i <= x / i; i ++)if(x % i ==0){
res = res / i *(i -1);while(x % i ==0) x /= i;}if(x >1) res = res / x *(x -1);return res;}
线性筛法求1~n的欧拉函数
voidget_eulers(int n)// 线性筛法求1~n的欧拉函数{
euler[1]=1;for(int i =2; i <= n; i ++){if(!st[i]){
primes[cnt ++]= i;
euler[i]= i -1;}for(int j =0; primes[j]<= n / i; j ++){int t = primes[j]* i;
st[t]=true;if(i % primes[j]==0){
euler[t]= euler[i]* primes[j];break;}
euler[t]= euler[i]*(primes[j]-1);}}}
辛普森积分公式
doublef(double x){// TODO: 实现所求的函数}doublesimpson(double l,double r)// 辛普森积分公式{auto mid =(l + r)/2;return(r - l)*(f(l)+4*f(mid)+f(r))/6;}doubleasr(double l,double r,double s)// 自适应{auto mid =(l + r)/2;auto left =simpson(l, mid), right =simpson(mid, r);if(fabs(left + right - s)< eps)return left + right;returnasr(l, mid, left)+asr(mid, r, right);}
计算几何常用函数
intsign(double x)// 符号函数{if(fabs(x)< eps)return0;// x为0,则返回0if(x <0)return-1;// x为负数,则返回-1return1;// x为正数,则返回1}intdcmp(double x,double y)// 比较两数大小{if(fabs(x - y)< eps)return0;// x == y, 返回0if(x < y)return-1;// x < y, 返回-1return1;// x > y, 返回1}
PDD operator+(PDD a, PDD b)// 向量加法{return{a.x + b.x, a.y + b.y};}
PDD operator-(PDD a, PDD b)// 向量减法{return{a.x - b.x, a.y - b.y};}
PDD operator*(PDD a,double t)// 向量数乘{return{a.x * t, a.y * t};}
PDD operator/(PDD a,double t)// 向量除以常数{return{a.x / t, a.y / t};}doubleoperator*(PDD a, PDD b)// 外积、叉积{return a.x * b.y - a.y * b.x;}doubleoperator&(PDD a, PDD b)// 内积、点积{return a.x * b.x + a.y * b.y;}doublearea(PDD a, PDD b, PDD c)// 以a, b, c为顶点的有向三角形面积{return(b - a)*(c - a);}doubleget_len(PDD a)// 求向量长度{returnsqrt(a & a);}doubleget_dist(PDD a, PDD b)// 求两个点之间的距离{returnget_len(b - a);}doubleproject(PDD a, PDD b, PDD c)// 求向量ac在向量ab上的投影{return((c - a)&(b - a))/get_len(b - a);}
PDD rotate(PDD a,double b)// 向量a逆时针旋转角度b{return{a.x *cos(b)+ a.y *sin(b),-a.x *sin(b)+ a.y *cos(b)};}
PDD norm(PDD a)// 矩阵标准化(将长度变成1){return a /get_len(a);}boolon_segment(PDD p, PDD a, PDD b)// 点p是否在线段ab上(包含端点a、b){return!sign((p - a)*(p - b))&&sign((p - a)&(p - b))<=0;}
PDD get_line_intersection(PDD p, PDD v, PDD q, PDD w)// 求两直线交点:p + vt, q + wt{auto u = p - q;auto t = w * u /(v * w);return p + v * t;}
求半平面交
struct Line // 直线{
PDD st, ed;// 直线上的两个点}line[N];int q[N];// 双端队列intsign(double x)// 符号函数{if(fabs(x)< eps)return0;// x为0,则返回0if(x <0)return-1;// x为负数,则返回-1return1;// x为正数,则返回1}intdcmp(double x,double y)// 比较两数大小{if(fabs(x - y)< eps)return0;// x == y, 返回0if(x < y)return-1;// x < y, 返回-1return1;// x > y, 返回1}
PDD operator+(PDD a, PDD b)// 向量加法{return{a.x + b.x, a.y + b.y};}
PDD operator-(PDD a, PDD b)// 向量减法{return{a.x - b.x, a.y - b.y};}doubleoperator*(PDD a, PDD b)// 外积、叉积{return a.x * b.y - a.y * b.x;}
PDD operator*(PDD a,double t)// 向量数乘{return{a.x * t, a.y * t};}doublearea(PDD a, PDD b, PDD c)// 以a, b, c为顶点的有向三角形面积{return(b - a)*(c - a);}
PDD get_line_intersection(PDD p, PDD v, PDD q, PDD w)// 求两直线交点:p + vt, q + wt{auto u = p - q;auto t = w * u /(v * w);return p + v * t;}
PDD get_line_intersection(Line a, Line b)// 求两直线交点{returnget_line_intersection(a.st, a.ed - a.st, b.st, b.ed - b.st);}boolon_right(Line& a, Line& b, Line& c)// bc的交点是否在a的右侧{auto o =get_line_intersection(b, c);returnsign(area(a.st, a.ed, o))<=0;}doubleget_angle(const Line& a)// 求直线的极角大小{returnatan2(a.ed.y - a.st.y, a.ed.x - a.st.x);}boolcmp(const Line& a,const Line& b)// 将所有直线按极角排序{double A =get_angle(a), B =get_angle(b);if(!dcmp(A, B))returnarea(a.st, a.ed, b.ed)<0;return A < B;}voidhalf_plane_intersection()// 半平面交,交集的边逆时针顺序存于q[]中{sort(line, line + cnt, cmp);int hh =0, tt =-1;for(int i =0; i < cnt; i ++){if(i &&!dcmp(get_angle(line[i]),get_angle(line[i -1])))continue;while(hh +1<= tt &&on_right(line[i], line[q[tt -1]], line[q[tt]])) tt --;while(hh +1<= tt &&on_right(line[i], line[q[hh]], line[q[hh +1]])) hh ++;
q[++ tt]= i;}while(hh +1<= tt &&on_right(line[q[hh]], line[q[tt -1]], line[q[tt]])) tt --;while(hh +1<= tt &&on_right(line[q[tt]], line[q[hh]], line[q[hh +1]])) hh ++;
q[++ tt]= q[hh];// 交集的边逆时针顺序存于q[]中// TODO: 求出半平面交后,根据题目要求求答案}