快速幂
1 typedef long long ll; 2 3 ll mod_pow(ll x,ll n,ll mod) 4 { 5 ll res=1; 6 while(n>0) 7 { 8 if(n&1)//if(n%2==1) 9 res=res*x%mod; 10 x=x*x%mod;//把x平方 11 n>>=1;//n=n/2 舍去最后一位 12 } 13 return res; 14 }
如果用来取模的数本身很大,快速幂会爆掉的话,加上快速乘来优化时间,以达到大数相乘取模:
1 typedef long long ll; 2 ll mod_pow(ll x,ll n,ll mod) 3 { 4 ll res=1; 5 while(n>0) 6 { 7 if(n&1) 8 res = mod_mulit(res,x,mod); 9 x = mod_multi(x,x,mod); 10 n >>= 1; 11 } 12 return res; 13 }
树状数组
查询区间和
引申:查询区间最值差
1 int lowbit(int x)//lowbit(x)表示2^k 2 { 3 return x&(-x); 4 } 5 6 void update(int x,int k)//在位置x增加k 7 { 8 while(x<=n) 9 { 10 c[x]+=k; 11 x+=lowbit(x); 12 } 13 } 14 15 int sum(int x) 16 { 17 int res=0; 18 while(x>0) 19 { 20 res+=c[x]; 21 x-=lowbit(x); 22 } 23 return res; 24 } 25 26 memset(c,0,sizeof(c));//输入记得清空 27 28 for(int i=1; i<=n; i++)//树状数组处理的是下标为1的数组 29 { 30 scanf("%d",&a[i]); 31 update(i,a[i]);//开始的时候每个元素初始值为0,对应位置加a[i]即可 32 }
最长公共子序列问题
1 char/int a[55],b[55]; 2 int dp[55][55];//dp若是太大,就利用滚动数组取余处理 3 int lcs() 4 { 5 //(char) 6 int la=strlen(a); 7 int lb=strlen(b); 8 for(int i=0;i) 9 { 10 for(int j=0;j ) 11 { 12 if(a[i]==b[j]) 13 dp[i+1][j+1]=dp[i][j]+1;//两个数组整体往后挪一位 14 else 15 dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]); 16 } 17 } 18 return dp[la][lb]; 19 }
欧几里得算法(辗转相除法)
可以调用__gcd(a,b);
或者自己写函数:
1 int gcd(int a,int b) 2 { 3 if(b==0) 4 return a; 5 return(b,a%b); 6 }
扩展欧几里得
求ax+by=gcd(a,b)的整数解x、y,同时可以求出最大公因数
1 int exgcd(int a,int b,int &x,int &y) 2 { 3 if(b==0) 4 { 5 x=1,y=0; 6 return a; 7 } 8 int yin=exgcd(b,a%b,x,y); 9 int t=x; 10 x=y; 11 y=t-(a/b)*y; 12 //x1=y2, 13 //y1=x2-(a/b)*y2; 14 return yin; 15 } 16 17 int main() 18 { 19 int a,b,x,y; 20 scanf("%d %d",&a,&b); 21 int maxx=exgcd(a,b,x,y);//最大公因数 22 return 0; 23 }
扩展欧几里得求逆元
以上两种解法均要满足a、p互质。
逆元定义:a*x ≡ 1 (mod p) 满足a乘以x对p取模等于1 ,此时称 x为a对p的逆元。
只有a与p互质才有逆元 ,互质即gcd(a,p)=1
问法:
求 :(a/b)%p;
转化成 (a*x)%p (即需要求b的逆元x) ;
即bx≡1modp;
设一个未知数y,则有bx+py=1(x即为所求逆元)(简介化成扩展欧几里得问题,因为b、p互质,所以gcd(b,p)=1 )。
如何求解:
1 int inverse(int b,int p)//求b的逆元x 2 { 3 int d=ex_gcd(b,p,x,y);//这里面的参数x就是所求逆元 4 if(d==1) 5 return (x%p+p)%p; 6 //防止逆元为负,若需要负数作为逆元则return x即可 7 return -1;//逆元不存在则返回-1 8 }
Dijkstra:
1 void dijkstra() 2 { 3 memset(book,0,sizeof(book)); 4 for(int i=1;i<=n;i++) 5 dis[i]=e[1][i]; 6 book[1]=1; 7 int u; 8 for(int i=2;i<=n;i++) 9 { 10 int minn=inf; 11 for(int j=1;j<=n;j++) 12 { 13 if(book[j]==0&&dis[j]<minn) 14 { 15 u=j; 16 minn=dis[j]; 17 } 18 } 19 book[u]=1; 20 for(int k=1;k<=n;k++) 21 { 22 if(e[u][k]dis[k]) 23 { 24 dis[k]=dis[u]+e[u][k]; 25 } 26 } 27 } 28 }
kruskal:
1 //kruskal 2 #include3 #include<string.h> 4 #include 5 #include 6 #include 7 #include 8 #include
prim:
1 //prim 2 #include3 #include<string.h> 4 #include 5 #include 6 #include 7 #include 8 #include
最短路和最小生成树区别:
最小生成树能够保证整个拓扑图的所有路径之和最小,但不能保证任意两点之间是最短路径。
最短路径是从一点出发,到达目的地的路径最小。
网络流
1 #include2 #include<string.h> 3 #include 4 #include 5 using namespace std; 6 #define inf 0x3f3f3f3f 7 const int N=220; 8 9 int e[N][N],pre[N]; 10 int n,m,s,t; 11 bool book[N]; 12 int maxflow; 13 14 15 bool bfs() 16 { 17 memset(book,false,sizeof(book)); 18 memset(pre,0,sizeof(pre)); 19 queue<int>Q; 20 Q.push(s); 21 book[s]=true; 22 23 while(!Q.empty()) 24 { 25 int p=Q.front(); 26 Q.pop(); 27 if(p==t) 28 return true; 29 for(int i=1; i<=n; i++) 30 { 31 if(book[i]==false) 32 { 33 if(e[p][i]>0) 34 { 35 book[i]=true; 36 pre[i]=p; 37 Q.push(i); 38 } 39 } 40 } 41 } 42 return false; 43 } 44 45 46 int solve() 47 { 48 maxflow=0; 49 while(1) 50 { 51 if(bfs()==false) 52 return maxflow; 53 int minn=inf; 54 for(int i=t; i!=s; i=pre[i]) 55 minn=min(minn,e[pre[i]][i]); 56 for(int i=t; i!=s; i=pre[i]) 57 { 58 e[pre[i]][i]-=minn; 59 e[i][pre[i]]+=minn; 60 } 61 maxflow+=minn; 62 } 63 } 64 65 int main() 66 { 67 int u,v,w; 68 int tt=1,ttt; 69 { 70 while(~scanf("%d %d",&m,&n)) 71 { 72 memset(e,0,sizeof(e)); 73 s=1,t=n; 74 for(int i=1; i<=m; i++) 75 { 76 scanf("%d %d %d",&u,&v,&w); 77 e[u][v]+=w; 78 } 79 printf("%d\n",solve()); 80 } 81 } 82 return 0; 83 }
kmp
查找模式串在原串中出现了几次
1 char s[10020],t[1000020]; 2 int lens,lent; 3 int nextt[10020]; 4 void getnext() 5 { 6 int i=0,j=-1; 7 nextt[0]=-1; 8 while(i<lens) 9 { 10 if(j<0||s[i]==s[j]) 11 { 12 nextt[++i]=++j; 13 } 14 else 15 j=nextt[j]; 16 } 17 } 18 19 int kmp() 20 { 21 int i=0,j=0,ans=0; 22 while(i<lent) 23 { 24 if(j<0||t[i]==s[j]) 25 { 26 i++; 27 j++; 28 } 29 else 30 j=nextt[j]; 31 if(j==lens) 32 { 33 ans++; 34 j=nextt[j]; 35 } 36 } 37 return ans; 38 }
0-1背包
1 //HDU-4508 2 #include3 #include<string.h> 4 #include 5 using namespace std; 6 int dp[2000000]; 7 int main() 8 { 9 int w[110],v[110]; 10 int n,i,m,j; 11 while(~scanf("%d",&n)) 12 { 13 memset(dp,0,sizeof(dp)); 14 for(i=0;i ) 15 { 16 scanf("%d %d",&w[i],&v[i]); 17 }//w幸福值 价值 v卡路里 重量 18 scanf("%d",&m); 19 for(i=0;i ) 20 { 21 for(j=v[i];j<=m;j++) 22 { 23 dp[j]=max(dp[j],dp[j-v[i]]+w[i]); 24 } 25 } 26 printf("%d\n",dp[m]); 27 } 28 return 0; 29 }
SPFA
1 #include2 #include 3 #include
线段树区间修改(A->B)、查询
1 #include2 #include 3 #include
线段树区间修改(A->A+B)、查询
1 //题意: 2 //C:对区间[l,r]每一个数+c; 3 // Q:查询区间[l,r]的所有元素的总和。 4 5 //线段树修改和查找的时间复杂度都是O(logn)。 6 //线段树基本思想:分治。 7 //线段树基本操作:建树、区间查询(最值;和)、区间修改(更新)、单点修改、单点查询。 8 9 #include10 #include<string.h> 11 #include 12 #include 13 #include
邻接表
1 struct node 2 { 3 int v,flow,nextt; 4 } e[M]; 5 6 int tot; 7 8 void add(int u,int v,int flow) 9 { 10 e[++tot].nextt=head[u]; 11 head[u]=tot; 12 e[tot].v=v; 13 e[tot].flow=flow; 14 15 e[++tot].nextt=head[v]; 16 head[v]=tot; 17 e[tot].v=u; 18 e[tot].flow=0; 19 }