gcd
int gcd(int a,int b)///辗转相除法求最大公约数 { int t = a; while(a%b) { a=b; b=t%b; t=a; } return b; }
或者
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
exgcd
扩展欧几里得算法
给予二整数 a 与 b, 必存在有整数 x 与 y 使得ax + by = gcd(a,b)
int exgcd(int a2,int b2,int &x,int &y) { if(b2==0) { x=1;y=0; return a2; } int ans = exgcd(b2,a2%b2,x,y); double temp=x; x=y; y=temp-a2/b2*y; return ans; ///返回的还是最大公约数 但是我们就方便求x和y }
int tocal(int a3,int b3) { int x0,y0; int gcd = exgcd(a3,b3,x0,y0); if(1%gcd!=0) return -1; ///gcd得等于1 ... x0*=1/gcd; b3=abs(b3); int ans = x0%b3; if (ans<=0) ans+=b3; return ans; }
lcm:
int lcm(int a,int b) { return a * b / gcd(a, b); }
那么求什么最大公约数最小公倍数 乘法逆元全都解决了
当然我当时也费尽心思研究了一番 为了RSA加密算法
01背包:
有一个容量为V的背包,现在有n件物品,每件物品所占空间为w[i],价值为v[i],求 背包中所装物品价值最大值
注意每个物品就一件
for(i=1;i<=n;i++) for(j=V;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]);
完全背包
完全背包是有n种物品,每种物品可以取无线多件,每件物品所占空间为w[i],价值为v[i]
for(i=1;i<=n;i++) for(j=w[i];j<=V;j++) f[j]=max(f[j],f[j-w[i]]+v[i]);
高精度加法:
#include<bits/stdc++.h> using namespace std; string a,b; string Precise_add(string a,string b){ int lena=a.length(); int lenb=b.length(); int aa,bb,sum,flag=0; while(lena>0){ aa=a[lena-1]-'0'; if(lenb>0) bb=b[lenb-1]-'0'; else bb=0; sum=aa+bb+flag; if(sum>=10){ a[lena-1]='0'+sum%10; flag=1; } else{ a[lena-1]='0'+sum; flag=0; } lena--; lenb--; } if(flag==1) a="1"+a; return a; } int main(){ cin>>a>>b; if(a.size()<b.size()) swap(a,b); cout<<Precise_add(a,b)<<endl; return 0; }
快速幂算法:
#include<bits/stdc++.h> #define ll long long using namespace std; ll Q(ll n,ll m){ ll res=1; while(m){ if(1&m) res=res*n; n=n*n; m>>=1; } return res; } int main(){ cout<<Q(5,12)<<endl; return 0; }
DFS:
#include<bits/stdc++.h> using namespace std; int a[105][105],b[105][105]; int n,m,startx,starty,endx,endy,ans=999999999; int next[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; void dfs(int x,int y,int step){ if(x==endx&&y==endy){ ans=min(ans,step); return; } for(int i=0;i<4;i++){ int xx=x+next[i][0]; int yy=y+next[i][1]; if(xx<1||xx>n||yy<1||yy>m) continue; if(a[xx][yy]==0&&b[xx][yy]==0){ b[xx][yy]=1; dfs(xx,yy,step+1); b[xx][yy]=0; } } return; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j]; cin>>startx>>starty>>endx>>endy; dfs(startx,starty,0); cout<<ans; return 0; }
最短路径 暴力
for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(e[i][j]>e[i][k]+e[k][j]) e[i][j]=e[i][k]+e[k][j]; } } }
底杰斯特拉算法
#include<bits/stdc++.h> #define MAX 100 // 矩阵最大容量 #define INF (~(0x1<<31)) // 最大值(即0X7FFFFFFF) #define LENGTH(a) (sizeof(a)/sizeof(a[0])) // 邻接矩阵 typedef struct _graph { char vexs[MAX]; // 顶点集合 int vexnum; // 顶点数 int edgnum; // 边数 int matrix[MAX][MAX]; // 邻接矩阵 }Graph, *PGraph; Graph* create_example_graph() { char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int matrix[][9] = { /*A*//*B*//*C*//*D*//*E*//*F*//*G*/ /*A*/ { 0, 12, INF, INF, INF, 16, 14}, /*B*/ { 12, 0, 10, INF, INF, 7, INF}, /*C*/ { INF, 10, 0, 3, 5, 6, INF}, /*D*/ { INF, INF, 3, 0, 4, INF, INF}, /*E*/ { INF, INF, 5, 4, 0, 2, 8}, /*F*/ { 16, 7, 6, INF, 2, 0, 9}, /*G*/ { 14, INF, INF, INF, 8, 9, 0}}; int vlen = LENGTH(vexs); int i, j; Graph* pG; // 输入"顶点数"和"边数" if ((pG=(Graph*)malloc(sizeof(Graph))) == NULL ) return NULL; memset(pG, 0, sizeof(Graph)); // 初始化"顶点数" pG->vexnum = vlen; // 初始化"顶点" for (i = 0; i < pG->vexnum; i++) pG->vexs[i] = vexs[i]; // 初始化"边" for (i = 0; i < pG->vexnum; i++) for (j = 0; j < pG->vexnum; j++) pG->matrix[i][j] = matrix[i][j]; // 统计边的数目 for (i = 0; i < pG->vexnum; i++) for (j = 0; j < pG->vexnum; j++) if (i!=j && pG->matrix[i][j]!=INF) pG->edgnum++; pG->edgnum /= 2; return pG; } void dijkstra(Graph G, int vs, int prev[], int dist[]) { int i,j,k; int min; int tmp; int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。 // 初始化 for (i = 0; i < G.vexnum; i++) { flag[i] = 0; // 顶点i的最短路径还没获取到。 prev[i] = 0; // 顶点i的前驱顶点为0。 dist[i] = G.matrix[vs][i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。 } // 对"顶点vs"自身进行初始化 flag[vs] = 1; dist[vs] = 0; // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。 for (i = 1; i < G.vexnum; i++) { // 寻找当前最小的路径; // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。 min = INF; for (j = 0; j < G.vexnum; j++) { if (flag[j]==0 && dist[j]<min) { min = dist[j]; k = j; } } // 标记"顶点k"为已经获取到最短路径 flag[k] = 1; // 修正当前最短路径和前驱顶点 // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。 for (j = 0; j < G.vexnum; j++) { tmp = (G.matrix[k][j]==INF ? INF : (min + G.matrix[k][j])); // 防止溢出 if (flag[j] == 0 && (tmp < dist[j]) ) { dist[j] = tmp; prev[j] = k; } } } // 打印dijkstra最短路径的结果 printf("dijkstra(%c): ", G.vexs[vs]); for (i = 0; i < G.vexnum; i++) printf(" shortest(%c, %c)=%d ", G.vexs[vs], G.vexs[i], dist[i]); } int main() { int prev[MAX] = {0}; int dist[MAX] = {0}; Graph* pG; pG = create_example_graph(); dijkstra(*pG, 3, prev, dist); return 0; }
欧拉筛筛素数
#include<bits/stdc++.h> using namespace std; void get_prime(vector<int> & prime,int upper_bound){ // 传引用 if(upper_bound < 2)return; vector<bool> Is_prime(upper_bound+1,true); for(int i = 2; i <= upper_bound; i++){ if(Is_prime[i]) prime.push_back(i); for(int j = 0; j < prime.size() and i * prime[j] <= upper_bound; j++){ Is_prime[ i*prime[j] ] = false; if(i % prime[j] == 0)break;// 保证了一个数只被筛一次。 } } } int main(){ vector<int> prime; get_prime(prime, 1000); for(vector<int> :: iterator it = prime.begin(); it not_eq prime.end(); it++) cout<<*it<<" "; return 0; }
读入优化
#include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin>>n; cout<<n; }
#include<stdio.h> #include<iostream> #include<string.h> const int MAX=4e6; using namespace std; int read(){ char ch=getchar(); int x=0,f=1; while(ch<'0'||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f; } int main(){ int x; cout<<read(); return 0; }
并查集
#include<bits/stdc++.h> #define ll long long using namespace std; int a[10000]; int S(int x){ if(a[x]==x) return x; else{ a[x]=S(a[x]); return a[x]; } } void B(int x,int y){ int xx=S(x); int yy=S(y); if(xx!=yy) a[yy]=xx; } int main(){ int n,sum=0;cin>>n; for(int i=1;i<=n;i++)a[i]=i; for(int i=1;i<=n;i++){ int x,y;cin>>x>>y; B(x,y); } for(int i=1;i<=n;i++) if(a[i]==i) sum++; cout<<sum; return 0; }
阶乘高精度
#include<bits/stdc++.h> using namespace std; int num[5000]; int gaojing(int num[],int n){ int len=1; num[0]=1; for(int i=1;i<=n;i++){ len=0; int p=0; int jw=0; while(num[p]!=-1){ num[p]*=i; num[p]+=jw; jw=0; if(num[p]>=10){ jw=num[p]/10; num[p]%=10; } p++; len++; } if(jw!=0){ while(jw){ num[p++]=jw%10; jw/=10; len++; } } } return len-1; } int main(){ int n; while(cin>>n){ memset(num,-1,sizeof(num)); int len=gaojing(num,n); for(len;len>=0;len--){ cout<<num[len]; } cout<<endl; } return 0; }
sort
字典序
#include<bits/stdc++.h> using namespace std; //algorithm string a[21]; bool cmp(string a,string b){ return a+b > b+a; int main(){ int n;cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++)cout<<a[i]<<" "; return 0; }
sstream 和 atoi
将字符串类型中的最前面数字转换为整数类型
#include<iostream> #include<sstream> using namespace std; int main(){ int x;string s; cin>>s; stringstream ss(s); ss>>x; cout<<x; return 0; }
#include<iostream> #include<sstream> #include<cstdlib> using namespace std; int main(){ int x;string s; cin>>s; x=atoi(s.c_str()); cout<<x; return 0; }
next_permutation()全排列函数
#include<iostream> #include<string> #include<algorithm> using namespace std; int main(){ string s="1234567";int sum=0; do{ cout<<s<<' '; sum++; }while(next_permutation(s.begin(),s.end())); cout<<sum<<' '; return 0; }
字符串查找函数 直接替代kmp算了
#include<cstring> #include<cstdio> #include<iostream> using namespace std; int main() { ////find函数返回类型 size_type string s("sbjkji"); string flag; string::size_type position; //find 函数 返回jk 在s 中的下标位置 position = s.find("ji"); if (position != s.npos) //如果没找到,返回一个特别的标志c++中用npos表示,我这里npos取值是4294967295, { printf("position is : %d " ,position); } else { printf("Not found the flag "); } position = s.find("good_girl"); if (position != s.npos) { printf("position is : %d " ,position); } else { printf("Not found the flag "); } }
strstr:
#include<bits/stdc++.h> /* * strstr函数 * 功能:在串中查找指定字符串的第一次出现 * 用法:char *strstr(char *strOne, char *strTwo); * 据说strstr函数和KMP的算法效率差不多 */ int main(int argc, const char * argv[]) { char strOne[] = "Hope my cold is better"; char strTwo[] = "cold"; char *ptr; ptr = strstr(strOne, strTwo); std::cout << ptr << ' '; //输出 cold is better return 0; }
优先队列
#include<iostream> #include <queue> using namespace std; int main() { //对于基础类型 默认是大顶堆 priority_queue<int> a; //等同于 priority_queue<int, vector<int>, less<int> > a; // 这里一定要有空格,不然成了右移运算符↓↓ priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆 priority_queue<string> b; for (int i = 0; i < 5; i++) { a.push(i); c.push(i); } while (!a.empty()) { cout << a.top() << ' '; a.pop(); } cout << endl; while (!c.empty()) { cout << c.top() << ' '; c.pop(); } cout << endl; b.push("abc"); b.push("abcd"); b.push("cbd"); while (!b.empty()) { cout << b.top() << ' '; b.pop(); } cout << endl; return 0; /* 结果 4 3 2 1 0 0 1 2 3 4 cbd abcd abc */ }
用pair做优先队列元素的例子:
规则:pair的比较,先比较第一个元素,第一个相等比较第二个。
#include <iostream> #include <queue> #include <vector> using namespace std; int main() { priority_queue<pair<int, int> > a; pair<int, int> b(1, 2); pair<int, int> c(1, 3); pair<int, int> d(2, 5); a.push(d); a.push(c); a.push(b); while (!a.empty()) { cout << a.top().first << ' ' << a.top().second << ' '; a.pop(); } }
字符串和数字的互相转换:
#include<bits/stdc++.h> using namespace std; int main () { int a;float b;long c; string d,e,f; // char d[10],e[10],f[10]; /* string to number */ stringstream ss; ss << "32"; ss >> a; ss.clear(); ss << "3.1415"; ss >> b; ss.clear(); ss << "567283"; ss >> c; ss.clear(); cout<<a<<","<<b<<","<<c<<endl; /* number to string */ ss << a; ss >> d; ss.clear(); ss << b; ss >> e; ss.clear(); ss << c; ss >> f; ss.clear(); cout<<d<<","<<e<<","<<f<<endl; return 0; }
bitset
#include <iostream> #include <bitset> using namespace std; const int MAXN = 32; bitset<MAXN> bt(11); int main() { cout << bt << ' '; // 输出 0000 ....1011 32位 cout <<bt.count() << ' '; //3个1输出3 cout << bt.size() << ' '; /* bt.flip() // 把 bt 中所有二进制位逐位取反 bt.flip(pos) // 把 bt 中在 pos 处的二进制位取反 bt[pos].flip() // 同上 bt.set() // 把 bt 中所有二进制位都置为 1 bt.set(pos) // 把 bt 中在 pos 处的二进制位置为 1 bt.reset() // 把 bt 中所有二进制位都置为 0 bt.reset(pos) // 把 bt 中在pos处的二进制位置为0 ~ | ^ & 都可以用 return 0; }
各种进制转换:https://blog.csdn.net/vir_lee/article/details/80645066
记忆化搜索:
https://blog.csdn.net/p2718756941/article/details/95473857
#include <bits/stdc++.h> using namespace std; int read() { int x=0,f=1; char ch=getchar();//getchar()读入单个字符(包括空格 ,换行符) while(ch<'0'||ch>'9'){//非数字(字符) if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48);//原二进制数向左平移x位,右边原位置以0补齐(位运算) ch=getchar(); } return x*f; }//快读 int n,m; int a[1010][1010]; int dp[1010][1010]; int ans; void CIN() { n=read(); m=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ a[i][j]=read(); dp[i][j]=1; } } return; } int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; bool in(int x,int y) { if(x>0&&y>0&&x<=n&&y<=m)return 1; return 0; } int DFS(int x,int y){ if(dp[x][y]>1)return dp[x][y]; for(int i=0;i<4;i++) { int xx=x+dir[i][0]; int yy=y+dir[i][1]; if(in(xx,yy)&&a[x][y]>a[xx][yy]) dp[x][y]=max(dp[x][y],DFS(xx,yy)+1); } return dp[x][y]; } int main(){ CIN(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans=max(ans,DFS(i,j)); cout<<ans<<endl; return 0; }
埃及分数
https://www.jianshu.com/p/da04c77e11d0
import java.io.BufferedReader; import java.io.InputStreamReader; //埃及分数 public class EgyptFraction { public static void main(String[] args) throws Exception{ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("输入分子"); int a = Integer.parseInt(bufferedReader.readLine()); System.out.println("输入分母"); int b = Integer.parseInt(bufferedReader.readLine()); //输入ab int e; //要求是如果分子大于1就可以拆分 do { e = b/a + 1; System.out.println("1/"+e); a = a * e - b; b = b * e; int maxDiv = maxComDiv(a,b); if(maxDiv > 1){ a /= maxDiv; b /= maxDiv; } }while (a > 1); System.out.println("1/"+b); } private static int maxComDiv(int a, int b) { int temp = 0; while(b != 0){ temp = a % b; a = b; b = temp; } return a; } }
十进制转26进制
#include <bits/stdc++.h> using namespace std; char str[27] = {0,'A','B','C','D','E','F','G','H','I','J','K' ,'L','M','N','O','P','Q','R','S','T','U','V', 'W','X','Y','Z'}; int main() { int num; string ans = ""; scanf("%d", &num); while(num) { ans += str[num % 26]; num /= 26; } for (int i = ans.size() - 1; i >= 0; i--) { cout << ans[i]; } return 0; }
数据类型取值范围
快速读入:
int read(){ int x=0,f=1; char ch=getchar();//getchar()读入单个字符(包括空格 ,换行符) while(ch<'0'||ch>'9'){//非数字(字符) if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48);//原二进制数向左平移x位,右边原位置以0补齐(位运算) ch=getchar(); } return x*f; }
解决爆栈 手动加栈:
#pragma comment(linker, “/STACK:1024000000,1024000000”)