沙雕的gcd:
//1.gcd int gcd(int a,int b) { return b?gcd(b,a%b):a; }
还有个exgcd:
//2.扩展gcd )extend great common divisor ll exgcd(ll l,ll r,ll &x,ll &y) { if(r==0) { x=1; y=0; return l; } else { ll d=exgcd(r,l%r,y,x); y-=l/r*x; return d; } }
求逆元:
//3.求a关于m的乘法逆元 ll mod_inverse(ll a,ll m) { ll x,y; if(exgcd(a,m,x,y)==1)//ax+my=1 return (x%m+m)%m; return -1;//不存在 }
快速幂:
//4.快速幂quick power ll qpow(ll a,ll b,ll m) { ll ans=1; ll k=a; while(b) { if(b&1)ans=ans*k%m; k=k*k%m; b>>=1; } return ans; }
快速乘(也叫二分乘法):
//5.快速乘,直接乘会爆ll时需要它,也叫二分乘法。 ll qmul(ll a,ll b,ll m) { ll ans=0; ll k=a; ll f=1;//f是用来存负号的 if(k<0) { f=-1; k=-k; } if(b<0) { f*=-1; b=-b; } while(b) { if(b&1) ans=(ans+k)%m; k=(k+k)%m; b>>=1; } return ans*f; }
中国剩余定理:
//6.中国剩余定理CRT (x=ai mod mi) ll china(ll n, ll *a,ll *m) { ll M=1,y,x=0,d; for(ll i = 1; i <= n; i++) M *= m[i]; for(ll i = 1; i <= n; i++) { ll w = M /m[i]; exgcd(m[i], w, d, y);//m[i]*d+w*y=1 x = (x + y*w*a[i]) % M; } return (x+M)%M; }
筛素数:
//7.筛素数,全局:int cnt,prime[N],p[N]; void isprime() { cnt = 0; memset(prime,true,sizeof(prime)); for(int i=2; i<N; i++) { if(prime[i]) { p[cnt++] = i; for(int j=i+i; j<N; j+=i) prime[j] = false; } } }
快速计算逆元:
//8.快速计算逆元 //补充:>>关于快速算逆元的递推式的证明<< void inverse() { inv[1] = 1; for(int i=2; i<N; i++) { if(i >= M) break; inv[i] = (M-M/i)*inv[M%i]%M; } }
组合数取模:
//9.组合数取模 n和m 10^5时,预处理出逆元和阶乘 ll fac[N]= {1,1},inv[N]= {1,1},f[N]= {1,1}; ll C(ll a,ll b) { if(b>a)return 0; return fac[a]*inv[b]%M*inv[a-b]%M; } void init() { //快速计算阶乘的逆元 for(int i=2; i<N; i++) { fac[i]=fac[i-1]*i%M; f[i]=(M-M/i)*f[M%i]%M; inv[i]=inv[i-1]*f[i]%M; } } n较大10^9,但是m较小10^5时, ll C(ll n,ll m) { if(m>n)return 0; ll ans=1; for(int i=1; i<=m; i++) ans=ans*(n-i+1)%M*qpow(i,M-2,M)%M; return ans; } //n和m特别大10^18时但是p较小10^5时用lucas
Lucas大组合取模:
//10.Lucas大组合取模 #define N 100005 #define M 100007 ll n,m,fac[N]= {1}; ll C(ll n,ll m) { if(m>n)return 0; return fac[n]*qpow(fac[m],M-2,M)%M*qpow(fac[n-m],M-2,M)%M;//费马小定理求逆元 } ll lucas(ll n,ll m) { if(!m)return 1; return(C(n%M,m%M)*lucas(n/M,m/M))%M; } void init() { for(int i=1; i<=M; i++) fac[i]=fac[i-1]*i%M; }
质因数分解:
//11.质因数分解 cin>>n; for(int i=2; i<=n; i++) { if(n==0)break; while(n%i==0) { n/=i; k[++ans]=i; } }
试除法:
//12.试除法 bool check(int n) { if(n==1)return false; for(int i=2; i<=sqrt(n); ++i) if(n%i==0)return false; return true; }
miller-rabin算法:
//13.miller-rabin算法 int test[10]= {2,3,5,7,11,13,19,23}; int qpow(int a,int b,int p) { int ans=1; while(b) { if(b&1)ans=1ll*ans*a%p; a=1ll*a*a%p,b>>=1; } return ans; } bool miller_rabin(int p) { if(p==1)return 0; int t=p-1; k=0; while(!(t&1))k++,t>>=1; for(int i=0; i<8; ++i) { if(p==test[i])return 1; long long a=qpow(test[i],t,p,),nx=a; for(int j=1; j<=k; ++j) { nx=(a*a)%p; if(nx==1&&a!=1&&a!=p-1) return 0; a-nx; } if(a!=1)return 0; } return 1; }
快读:
//14.快读 inline int read() { int s=0,w=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘)w=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return s*w; }
spfa_dfs:
//15.spfa_dfs int spfa_dfs(int u) { vis[u]=1; for(int k=f[u]; k!=0; k=e[k].next) { int v=e[k].v,w=e[k].w; if( d[u]+w < d[v] ) { d[v]=d[u]+w; if(!vis[v]) { if(spfa_dfs(v)) return 1; } else return 1; } } vis[u]=0; return 0; }
spfa_dfs:
//16、spfa_bfs int spfa_bfs(int s) { queue <int> q; memset(d,0x3f,sizeof(d)); d[s]=0; memset(c,0,sizeof(c)); memset(vis,0,sizeof(vis)); q.push(s); vis[s]=1; c[s]=1; //顶点入队vis要做标记,另外要统计顶点的入队次数 int OK=1; while(!q.empty()) { int x; x=q.front(); q.pop(); vis[x]=0; //队头元素出队,并且消除标记 for(int k=f[x]; k!=0; k=nnext[k]) { //遍历顶点x的邻接表 int y=v[k]; if( d[x]+w[k] < d[y]) { d[y]=d[x]+w[k]; //松弛 if(!vis[y]) { //顶点y不在队内 vis[y]=1; //标记 c[y]++; //统计次数 q.push(y); //入队 if(c[y]>NN) //超过入队次数上限,说明有负环 return OK=0; } } } } return OK; }
杂:
//cin,优化 cin.tie(0); ios_base::sync_with_stdio(false); //输出优化: void print( int k ) { num = 0; while( k > 0 ) ch[++num] = k % 10, k /= 10; while( num ) putchar( ch[num--]+48 ); putchar( 32 ); }
RMQ:
//区间查询最值问题 //预处理 void rmq_init() { for(int i=1; i<=N; i++) dp[i][0]=arr[i];//初始化 for(int j=1; (1<<j)<=N; j++) for(int i=1; i+(1<<j)-1<=N; i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]); } //查询 int rmq(int l,int r) { int k=log2(r-l+1); return min(dp[l][k],dp[r-(1<<k)+1][k]); }
RMQ转LCA:
int euler[MAXN*2]; int dep[MAXN*2]; int pos[MAXN]; int top; int rmq[MAXN*2][16]; void dfs(int u,int depth,int fa) { euler[++top]=u; dep[top]=depth; pos[u]=top; INE(i,u,e) { int v=e[i].v; if(v==fa) continue; dfs(v,depth+1,u); euler[++top]=u; dep[top]=depth; } } void RMQinit() { rep(i,1,top) rmq[i][0]=i; rep(j,1,16) rep(i,1,top) if(i+(1<<j)-1<=top) { if(dep[rmq[i][j-1]]<dep[rmq[i+(1<<j-1)][j-1]]) rmq[i][j]=rmq[i][j-1]; else rmq[i][j]=rmq[i+(1<<j-1)][j-1]; } } int RMQ(int l,int r) { int len=r-l+1; int LOG=0; for(;1<<LOG+1<=len;LOG++); if(dep[rmq[l][LOG]]<dep[rmq[r-(1<<LOG)+1][LOG]]) return rmq[l][LOG]; else return rmq[r-(1<<LOG)+1][LOG]; } void LCAinit() { dfs(1,0,-1); RMQinit(); } int LCA(int u,int v) { if(pos[u]>pos[v]) swap(u,v); return euler[RMQ(pos[u],pos[v])]; }
tarjan求LCA:
//并查集记录父亲的数组. int father[MAXN]; //并查集的查找函数,有路径压缩功能. int find ( int x ) { return father[x] == x ? x : father[x] = find ( father[x]); } //采用邻接表存储 struct { int v,next,lca,u; } e[2][MAXN<<2]; //分别记录边对和查询数对 int head[2][MAXN]; int cc; //添加边,flag表示模式 void add ( int flag , int u , int v ) { e[flag][cc].u = u; e[flag][cc].v = v; e[flag][cc].next = head[flag][u]; head[flag][u] = cc++; } //标记当前点是否访问过 bool visited[MAXN]; void LCA ( int u ) { father[u] = u; visited[u] = true; //深度优先搜索整棵树 for ( int i = head[0][u]; i != -1 ; i = e[0][i].next ) { int v = e[0][i].v; if ( visited[v] ) continue; LCA ( v ); //从叶节点开始,逐层标记父节点 father[v] = u; } //当前子树已经维护,利用并查集找到当前子树的查询数对的LCA for ( int i = head[1][u]; i != -1 ; i = e[1][i].next ) { int v = e[1][i].v; if ( !visited[v] ) continue; //如果当前u,v都已经访问过,那么一定维护过的子树中 e[1][i].lca = e[1][i^1].lca = find ( v ); } }
倍增求LCA:
#include<bits/stdc++.h> using namespace std; struct node { int t,nex; } e[500001<<1]; int depht[500001],father[500001][22],lg[500001],head[500001]; int tot; inline void add(int x,int y) { e[++tot].t=y; e[tot].nex=head[x]; head[x]=tot; } inline void dfs(int now,int fath) { depht[now]=depht[fath]+1; father[now][0]=fath; for(register int i=1; (1<<i)<=depht[now]; ++i) father[now][i]=father[father[now][i-1]][i-1]; for(register int i=head[now]; i; i=e[i].nex) { if(e[i].t!=fath)dfs(e[i].t,now); } } inline int lca(int x,int y) { if(depht[x]<depht[y]) swap(x,y); while(depht[x]>depht[y]) x=father[x][lg[depht[x]-depht[y]]-1]; if(x==y) return x; for(register int k=lg[depht[x]]; k>=0; --k) if(father[x][k]!=father[y][k]) x=father[x][k],y=father[y][k]; return father[x][0]; } int n,m,s; int main() { scanf("%d%d%d",&n,&m,&s); for(register int i=1; i<=n-1; ++i) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(s,0); for(register int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i); for(register int i=1; i<=m; ++i) { int x,y; scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }
基环树找环:
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define MAXN 1000010 #define MAXM 5010 inline int read() { int x = 0,ff = 1;char ch = getchar(); while(!isdigit(ch)) { if(ch == ‘-‘) ff = -1; ch = getchar(); } while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * ff; } inline void write(int x) { if(x < 0) putchar(‘-‘),x = -x; if(x > 9) write(x / 10); putchar(x % 10 + ‘0‘); } int a,ti = 0,cnt = 0,fa[MAXN],vis[MAXN],loop[MAXN]; int lin[MAXN],tot = 0; struct edge { int y,v,next; }e[MAXN]; inline void add(int xx,int yy,int vv) { e[++tot].y = yy; e[tot].v = vv; e[tot].next = lin[xx]; lin[xx] = tot; } void get_loop(int x) { vis[x] = ++ti; for(int i = lin[x],y;i;i = e[i].next) { if((y = e[i].y) == fa[x]) continue; if(vis[y]) { if(vis[y] < vis[x]) continue; loop[++cnt] = y; for(y = fa[y];y != fa[x];y = fa[y]) loop[++cnt] = y; } else fa[y] = x,get_loop(y); } } int main() { a = read(); for(int i = 1;i <= a;++i) { int y,v; y = read(); v = read(); add(i,y,v); add(y,i,v); } get_loop(1); for(int i = 1;i <= cnt;++i) write(loop[i]),putchar(‘ ‘); return 0; }
有关最短路的东西:
//一、多源最短路算法——Floyd 算法 //floyd 算法主要用于求任意两点间的最短路径,也称最短最短路径问题 //核心代码: void floyd() { int i, j, k; for (k = 1; k <= n; ++k) //遍历所有的中间点 for (i = 1; i <= n; ++i) //遍历所有的起点 for (j = 1; j <= n; ++j) //遍历所有的终点 if (e[i][j] > e[i][k] + e[k][j]) //如果当前i-->j的距离大于i-->k--->j的距离之和 e[i][j] = e[i][k] + e[k][j];//更新从i--->j的最短路径 } // 时间复杂度:O(N^3) // 不能使用的情况:边中含有负权值 //二、单源最短路径算法——dijkstra //1、思想描述:当Q(一开始为所有节点的集合)非空时, //不断地将Q中的最小值u取出,然后放到S(最短路径的节点的集合)集合中, //然后遍历所有与u邻接的边,如果可以进行松弛, //则对便进行相应的松弛。。。 //2、实现 /** * 返回从v---->到target的最短路径 */ int dijkstra(int v) { int i; for(i = 1 ; i <= n ; ++i) { //初始化 s[i] = 0;//一开始,所有的点均为被访问过 dis[i] = map[v][i]; } dis[v] = 0; s[v] = true; for(i = 1 ; i < n ; ++i) { int min = inf,pos,j; for(j = 1 ; j <= n ; ++j)//寻找目前的最短路径的最小点 if(!s[j] && dis[j] < min) { min = dis[j]; pos = j; } s[pos] = 1; for(j = 1 ; j <= n ; j++)//遍历u的所有的邻接的边 if(!s[j] && dis[j] > dis[pos] + map[pos][j]) dis[j] = dis[pos] + map[pos][j];//对边进行松弛 } return dis[target]; } //3.基本结构 int s[maxn];//用来记录某一点是否被访问过 int map[maxn][maxn];//地图 int dis[maxn];//从原点到某一个点的最短距离(一开始是估算距离) //4.条件:使用dijkstra解决的题目一般有以下的特征: //给出点的数目、边的数目、起点和终点、边的信息(,并且边不包含负边权的值).求从起点到终点的最短路径的距离 //起点:用于dijkstra(int v)中的v //终点:用于return dis[target]中的target //边的信息:用于初始化map[][] //三:使用 bellmen-ford 算法 //算法介绍: //思想:其实bellman-ford的思想和dijkstra的是很像的, //其关键点都在于不断地对边进行松弛。 //而最大的区别就在于前者能作用于负边权的情况。 //其实现思路还是在求出最短路径后, //判断此刻是否还能对便进行松弛, //如果还能进行松弛,便说明还有负边权的边 //实现: bool bellmen_ford() { for(int i=1; i<=n; i++) dis[i]=inf; dis[source]=0; for(int i=1; i<n; i++) { for(int j=1; j<=m; j++) { dis[edge[j].v] = min(dis[edge[j].v],dis[edge[j].u] + edge[j].weight); dis[edge[j].u] =min(dis[edge[j].u],dis[edge[j].v] + edge[j].weight) ; } } for(j = 1 ; j <= m ; ++j) //判断是否有负边权的边 if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight) return false; return true; } //基本结构: struct Edge{ int u,v,weight; }edge[maxn]; int dis[maxn]; //条件:其实求最短路径的题目的基本条件都是点数,边数,起点终点 //四、使用spfa算法来解决 //思想:用于求单源最短路经,可以适用于负边权的情况(不过他已经死了
原文地址:https://www.cnblogs.com/ydclyq/p/11663597.html
时间: 2024-10-29 11:36:46