ACM算法模板
2016-07-28 23:53
344 查看
1.头文件
2.筛选法求素数
3.快速幂
快速幂取模
int fun(int a, int b, int n) {
int t = 1, y = a;
while (b != 0){
y %= n;
if (b % 2 == 1)
t = t%n*y%n;
y = y*y%n;
b = b >> 1;
}
return t;
}
4.模拟大数相加
模拟大数阶乘:
5.最大公约数
6.全排列
7.二分搜索
8.背包问题
9.LIS最长上升子序列
10.最长公共子序列
11.并查集
12.并查集的MST——.Kruskal算法 (稀疏图)
第一步:点、边、加入vector,把所有边按从小到大排序
第二步:下面代码
13.并查集的MST——Prim算法 (稠密图)
时间复杂度:O(n方)
Prim算法优化版,用堆
时间复杂度:O(elgn)
14.单源最短路算法——Dijkstra
适用于边权为正、求从单个源点出发,到所有节点的最短路 有向图或者无向图
二维数组+路径打印:
优化版:时间复杂度 O(elbn)
15.Bellman-Ford算法的一种队列优化---SPFA 算法
时间复杂度减少,而且也可以处理负环的情况
16.Floyd-Warshall算法——任意点对最短路算法
求图中任意两点的最短距离的算法
17.染色法判断二分图
18.匈牙利算法 求解最大匹配问题
递归 腾
dfs版:
19.求多边形面积
20.向量基本用法
21.判断线段相交
22.求三角形外心
23.极角排序
24.kmp算法
kmp扩展
25.字典树
26.AC自动机
27.线段树
点更新
区间更新
28.中国剩余定理
#define _CRT_SBCURE_MO_DEPRECATE #include<iostream> #include<stdlib.h> #include<stdio.h> #include<cmath> #include<algorithm> #include<string> #include<string.h> #include<set> #include<queue> #include<stack> #include<functional> using namespace std; const int maxn = 100 + 10; const int INF = 0x3f3f3f3f;<span id="transmark" style="display: none; width: 0px; height: 0px;"></span>
2.筛选法求素数
伪代码 IS_PRIME(A) for each i less than A.length + 1 A[i] = 0 for i = 2 to A.length + 1 if A[i] = 0 for all multiples j of i,less than upper bound A[j] <- 1 代码 for (int i = 2; i < n; i++) { if (a[i] == 0) { for (int j = i + 1; j <= 10000; j = j + i) { a[j] = 1; } } }
3.快速幂
快速幂公式: typedef long long LL;//视情况定类型 LL fun(LL x, LL n) { LL res = 1; while (n > 0) { if (n & 1)//&按位与判奇偶 4>>1 = 4/2 2<<1 = 2*2 res = (res*x);//求幂,所以无取模 x = x*x; n >>= 1; } return res; }
快速幂取模
int fun(int a, int b, int n) {
int t = 1, y = a;
while (b != 0){
y %= n;
if (b % 2 == 1)
t = t%n*y%n;
y = y*y%n;
b = b >> 1;
}
return t;
}
4.模拟大数相加
<pre name="code" class="cpp">string add(string s1, string s2) { if (s1 == ""&&s2 == "") return "0"; if (s1 == "") return s2; if (s2 == "") return s1; string max = s1, min = s2; if (s1.length() < s2.length()) { max = s2; min = s1; } int a = max.length() - 1; int b = min.length() - 1; for (int i = b; i >= 0; i--) { max[a--] += min[i] - '0';//a一直在减 } for (int i = max.length(); i > 0; i--) { if (max[i] > '9') { max[i] = max[i] - 10; max[i - 1]++; } } if (max[0] > '9') { max[0] -= 10; max = '1' + max; } return max; }
模拟大数阶乘:
int main() { int large_num[16326] = { 1 }; int num, zero = 0; int i, j, k, n; int top; scanf("%d", &num); for (i = 2, top = 1; i <= num; i++){ k = i; while (k % 10 == 0){ k /= 10; zero++; } for (j = 0; j < top; j++) large_num[j] *= k; for (n = 0; ; n++){ large_num[n + 1] += large_num / 10; large_num %= 10; if (n + 1 == top){ if (large_num[n + 1] != 0) top++; else break; } } } for (i = top - 1; i >= 0; i--) printf("%d", large_num[i]); for (i = 0; i < zero; i++) printf("0"); printf("\n"); return 0; }
5.最大公约数
公约数求公倍数:乘积/最大公约数 int gad(int da, int xiao) { int temp; while (xiao!=0) { temp = da%xiao; da = xiao; xiao = temp; } return (da); }
6.全排列
求1-n的全排列 void Perm(int list[], int k, int m) { if (k == m - 1) { for (int i = 0; i < m; i++) { printf("%d", list[i]); } printf("\n"); } else { for (int i = k; i < m; i++) { swap(list[k], list[i]); Perm(list, k + 1, m); swap(list[k], list[i]); } } }
7.二分搜索
int bsearch(int *A, int x, int y, int v) { x为最开始元素 y是末尾元素的下一个数 v是要找的数 int m; while (x < y) { m = x + (y - x) / 2; if (A[m] >= v) y = m; //如果要替换为 upper_bound, 改为:if(A[m] <= v) x = m+1; else y = m; else x = m + 1; } return x; } //最后x == y // 如果没有找到 135577找6,返回7 // 如果找有多少的v,可以用lower_bound查找一遍,upper_bound查找一遍,下标相减 // lower_bound(a,a+n,v)返回数组中最后一个v的下一个数的地址 //upper_bound(a,a+n,v)返回数组中第一个v的地址 //如果a+n内没有找到v或v的下一个地址,返回a+n的地址 //lower_bound(a, a + n, v)-upper_bound(a, a + n, v)返回数组中v的个数
8.背包问题
01背包: void bag01(int cost,int weight) { for(i=v;i>=cost;i--) dp[i] = max(dp[i], dp[i-cost]+weight); } 完全背包: void complete(int cost,int weight) { for(i=cost;i<=v;i++) dp[i] = max(dp[i], dp[i-cost]+weight); } 多重背包: void multiply(int cost,int weight,int amount) { if(cost*amount>=v) complete(cost,weight); else{ k=1; while(k<amount){ bag01(k*cost,k*weight); amount-=k; k+=k; } bag01(cost*amount,weight*amount); } }
9.LIS最长上升子序列
状态转移dp[i] = max{ 1.dp[j] + 1 }; j<i;a[j]<a[i]; d[i]是以i结尾的最长上升子序列 与i之前的 每个a[j]<a[i]的 j的位置的 最长上升子序列+1后 的值比较 void solve(){ // 参考挑战程序设计入门经典; for(int i = 0; i < n; ++i){ dp[i] = 1; for(int j = 0; j < i; ++j){ if(a[j] < a[i]){ dp[i] = max(dp[i], dp[j]+1); } } } } 优化方法 //dp[i]表示长度为i+1的上升子序列的最末尾元素; //找到第一个比dp末尾大的,代替 void solve() { fill(dp, dp + n, INF); for (int i = 0; i < n; i++) { *lower_bound(dp, dp + n, a[i]) = a[i];//返回一个指针 } printf("%d\n", *lower_bound(dp, dp + n, INF) - dp; } //函数lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个不小于value 的值。
10.最长公共子序列
求最长公共子序列 递推 void solve() { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (s1[i] == s2[j]) { dp[i + 1][j + 1] = dp[i][j] + 1; } else { dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]); } } } }
11.并查集
int father[100];//储存i的father父节点 void makeSet() { for (int i = 0; i < 100; i++) father[i] = i; } int findRoot(int x) { //递归查找根节点 if (father[x] == x) return x; else return findRoot(father[x]); } int Find(int x) { // 路径压缩 递推 优化:关键在于在路径上的每个节点都可以直接连接到根上 if (father[x] != x) father[x] = Find(father[x]); return father[x]; } int DFind(int x) {//路径压缩 迭代 最优版 int root = x; //根节点 while (root != father[root]) { //寻找根节点 root = father[root]; } while (x != root) { int tmp = father[x]; father[x] = root; //根节点赋值 x = tmp; } return root; } void Union(int x, int y) {//将x所在的集合和y所在的集合整合起来形成一个集合。 int a, b; a = findRoot(x); b = findRoot(y); father[a] = b; //y连在x的根节点上 或father[b] = a为x连在y的根节点上; }
12.并查集的MST——.Kruskal算法 (稀疏图)
第一步:点、边、加入vector,把所有边按从小到大排序
第二步:下面代码
void Kruskal() { ans = 0; for (int i = 0; i<len; i++) { if (Find(edge[i].a) != Find(edge[i].b)) { Union(edge[i].a, edge[i].b); ans += edge[i].len; } } }
13.并查集的MST——Prim算法 (稠密图)
时间复杂度:O(n方)
void Init() { for (int i = 0; i < maxn; ++i) { G[i].clear(); intree[i] = false; mindist[i] = INF;//初始化为最大值,因为开始的时候F为空,到V的任意节点都不连通,用INF表示 } } int Prim(int s)//s是第一个加入生成树的结点 { int ans = 0; int vex, addNode, tempMin;//加入集合F中的节点 intree[s] = true;//加入生成树 for (unsigned int i = 0; i < G[s].size(); ++i) {//更新mindistG[s][i].vex即所有与s连通的节点vex vex = G[s][i].vex; mindist[vex] = G[s][i].weight; } for (int nodeNum = 1; nodeNum <= n - 1; ++nodeNum) {//对于集合V中剩余的n-1个节点 tempMin = INF; for (int i = 1; i <= n; ++i) {//从集合V中找出到F最小距离的边, if (intree[i] == false && mindist[i] < tempMin) { tempMin = mindist[i]; addNode = i; } } intree[addNode] = true;//addNode 加入集合F ans += tempMin;//此时tempMin是最小权值 for (unsigned int i = 0; i < G[addNode].size(); ++i) {//addNode加入集合F后更新F到V的最小距离,这里最关键! vex = G[addNode][i].vex; if (intree[vex] == false && G[addNode][i].weight < mindist[vex]) mindist[vex] = G[addNode][i].weight; } } return ans; }
Prim算法优化版,用堆
时间复杂度:O(elgn)
struct node { int v, len; node(int v = 0, int len = 0) :v(v), len(len) {} bool operator < (const node &a)const { //加入队列的元素自动按距离从小到大排序 return len> a.len; } }; void init() { for (int i = 0; i<maxn; i++) { G[i].clear(); dis[i] = INF; vis[i] = false; } } void Prim(int s) { priority_queue<node>Q;//定义优先队列 int ans = 0; Q.push(node(s,0)); //起点加入队列 while (!Q.empty()) { node now = Q.top(); Q.pop(); //取出距离最小的点 int v = now.v; if (vis[v]) continue; //同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。 vis[v] = true; //标记一下 ans += now.len; for (int i = 0; i<G[v].size(); i++) { //开始更新 int v2 = G[v][i].v; int len = G[v][i].len; if (!vis[v2] && dis[v2] > len) { dis[v2] = len; Q.push(node(v2, dis[v2])); //更新的点加入队列并排序 } } } printf("%d\n", ans); }
14.单源最短路算法——Dijkstra
适用于边权为正、求从单个源点出发,到所有节点的最短路 有向图或者无向图
void init() { for (int i = 0; i < maxn; i++) { intree[i] = false; G[i].clear(); mindist[i] = INF; } } int Perim(int s, int t) { int ans = 0; int vex, addNode, tempMin; intree[s] = true; mindist[s] = 0; for (int i = 0; i < G[s].size(); i++) {//找开始点周围的路径并初始化 vex = G[s][i].vex; mindist[vex] = Min(mindist[vex], G[s][i].weight); } for (int nodeNum = 1; nodeNum <= n - 1; nodeNum++) {//向周围n-1个点找 tempMin = INF; for (int i = 0; i < n; i++) { if (intree[i] == false && mindist[i] < tempMin) {//寻找最短路径 tempMin = mindist[i]; addNode = i; } } intree[addNode] = true; for (int i = 0; i < G[addNode].size(); i++) {//更新 vex = G[addNode][i].vex; if (intree[vex] == false && mindist[addNode] + G[addNode][i].weight < mindist[vex]) mindist[vex] = mindist[addNode] + G[addNode][i].weight; } } return mindist[t]; }
二维数组+路径打印:
#include<stdio.h> #include<string.h> #define INF 100000000 #define maxn 1001 bool vis[maxn]; int adj[maxn][maxn],dis[maxn],pre[maxn];//pre[]记录前驱 int n, m; void dijkstra(int v) { int i, j, u , min; for(i=0;i<=n;i++) { dis[i]=adj[v][i]; vis[i]=0; //if(i!=v&&adj[v][i]!=INF)pre[i] = v; // else pre[i] = -1; } vis[v]=1;dis[v]=0; for(i=1;i<n;i++) { min = INF; for(j=1;j<=n;j++) { if(!vis[j]&&min > dis[j]) { min = dis[j]; u = j; } } if(min == INF)break; vis[u]=1; for(j=1;j<=n;j++) { if(!vis[j]&&adj[u][j]!=INF&&dis[u]+adj[u][j]<dis[j]) { dis[j] = adj[u][j] + dis[u]; // pre[j] = u; } } } } int main() { int i, j, x, y, w; while(~scanf("%d%d",&n,&m)&&n) { for(i=0;i<=n;i++) { for(j=0;j<=n;j++) if(i==j)adj[i][j]=0; else adj[i][j] = INF; } while(m--) { scanf("%d%d%d",&x,&y,&w); adj[x][y] = w; adj[y][x] = w; } dijkstra(0); printf("%d\n",dis ); //以下为输出路径 /*int p, len=0, ans[maxn]; p = n-1; while(p!=0) { ans[len++] = p; p = pre[p]; } printf("0->"); for(i=len-1;i>=0;i--) printf("%d",ans[i]); puts(""); */ } return 0; }
优化版:时间复杂度 O(elbn)
struct node { int v, len; node(int v = 0, int len = 0) :v(v), len(len) {} bool operator < (const node &a)const { //距离从小到大排序 return len > a.len; } }; vector<node>G[maxn]; bool vis[maxn]; int dis[maxn]; void init() { for (int i = 0; i<maxn; i++) { G[i].clear(); vis[i] = false; dis[i] = INF; } } int dijkstra_heap(int s, int e) { priority_queue<node>Q; Q.push(node(s, 0));//加入队列并排序 dis[s] = 0; while (!Q.empty()) { node now = Q.top(); //取出当前最小的 Q.pop(); int v = now.v; if (vis[v]) continue; //如果标记过了 直接continue vis[v] = true; for (int i = 0; i<G[v].size(); i++) { //更新 int v2 = G[v][i].v; int len = G[v][i].len; if (!vis[v2] && dis[v2] > dis[v] + len) { dis[v2] = dis[v] + len; Q.push(node(v2, dis[v2])); } } } return dis[e]; }
15.Bellman-Ford算法的一种队列优化---SPFA 算法
时间复杂度减少,而且也可以处理负环的情况
//不断的将s的邻接点加入队列,取出不断的进行松弛操作,直到队列为空 //如果一个结点被加入队列超过n-1次,那么显然图中有负环 void Init() { for(int i = 0 ; i < maxn ; ++i){ G[i].clear(); dist[i] = INF; } } int SPFA(int s,int e) { int v1,v2,weight; queue<int> Q; memset(inqueue,false,sizeof(inqueue));//标记是否在队列中 memset(cnt,0,sizeof(cnt));//加入队列的次数 dist[s] = 0; Q.push(s);//起点加入队列 inqueue[s] = true;//标记 while(!Q.empty()){ v1 = Q.front(); Q.pop(); inqueue[v1] = false;//取消标记 for(int i = 0 ; i < G[v1].size() ; ++i){//搜索v1的链表 v2 = G[v1][i].vex; weight = G[v1][i].weight; if(dist[v2] > dist[v1] + weight){ //松弛操作 dist[v2] = dist[v1] + weight; if(inqueue[v2] == false){ //再次加入队列 inqueue[v2] = true; //cnt[v2]++; 判负环 //if(cnt[v2] > n) return -1; Q.push(v2); } } } } return dist[e]; }
16.Floyd-Warshall算法——任意点对最短路算法
求图中任意两点的最短距离的算法
for (int i = 0; i < n; i++) {//初始化为0 for (int j = 0; j < n; j++) scanf("%lf", &dis[i][j]); } for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } } }
17.染色法判断二分图
int bipartite(int s) { int u, v; queue<int>Q; color[s] = 1; Q.push(s); while (!Q.empty()) { u = Q.front(); Q.pop(); for (int i = 0; i < G[u].size(); i++) { v = G[u][i]; if (color[v] == 0) { color[v] = -color[u]; Q.push(v); } else if (color[v] == color[u]) return 0; } } return 1; }
18.匈牙利算法 求解最大匹配问题
递归 腾
vector<int>G[maxn]; bool inpath[maxn];//标记 int match[maxn];//记录匹配对象 void init() { memset(match, -1, sizeof(match)); for (int i = 0; i < maxn; i++) { G[i].clear(); } } bool findpath(int k) { for (int i = 0; i < G[k].size(); i++) { int v = G[k][i]; if (!inpath[v]) { inpath[v] = true; if (match[v] == -1 || findpath(match[v])) {//递归 match[v] = k;//即匹配对象是“k妹子”的 return true; } } } return false; } void hungary() { int cnt = 0; for (int i = 1; i <= m; i++) { //m为需要匹配的“妹子”数 memset(inpath, false, sizeof(inpath));//每次都要初始化 if (findpath(i)) cnt++; } cout << cnt << endl; }
dfs版:
int v1, v2; bool Map[501][501]; bool visit[501]; int link[501]; int result; bool dfs(int x) { for (int y = 1; y <= v2; y++) { if (Map[x][y] && !visit[y]) { visit[y] = true; if (link[y] == 0 || dfs(link[y])) { link[y] = x; return true; } } } return false; } void Search() { for (int x = 1; x <= v1; x++) { memset(visit,false,sizeof(visit)); if (dfs(x)) result++; } } <pre><span style="color:#000000;">memset(Map,</span><span style="color:#800080;">0</span>,<span style="color:#0000ff;">sizeof</span><span style="color:#000000;">(Map));</span>
19.求多边形面积
struct node { double x;//横坐标 double y;//纵坐标 }; node G[maxn]; int n; double Cross(node a, node b) { //叉积计算 return a.x*b.y - a.y*b.x; } int main() { while (scanf("%d", &n) != EOF && n) { for (int i = 0; i < n; i++) scanf("%lf %lf", &G[i].x, &G[i].y); double sum = 0; G .x = G[0].x; G .y = G[0].y; for (int i = 0; i < n; i++) { sum += Cross(G[i], G[i + 1]); } //或者 //for (int i = 0; i < n; i++) { //sum += fun(G[i], G[(i + 1)% n]); //} sum = sum / 2.0; printf("%.1f\n", sum); } system("pause"); return 0; }
20.向量基本用法
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); } Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); } Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); } Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); } double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }//向量点乘 double Length(Vector A) { return sqrt(Dot(A, A)); } //向量模长 double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } //向量之间夹角 double Cross(Vector A, Vector B) { //叉积计算 公式 return A.x*B.y - A.y*B.x; } Vector Rotate(Vector A, double rad)//向量旋转 公式 { return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad)); } Point getLineIntersection(Point P, Vector v, Point Q, Vector w)//两直线交点t1 t2计算 公式 { Vector u = P - Q; double t = Cross(w, u) / Cross(v, w); //求得是横坐标 return P + v*t; //返回一个点 }
21.判断线段相交
struct node { double x,y; }; node P[35][105]; double Cross_Prouct(node A,node B,node C) // 计算BA叉乘CA; { return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x); } bool Intersect(node A,node B,node C,node D) // 通过叉乘判断线段是否相交; { if(min(A.x,B.x)<=max(C.x,D.x)&& // 快速排斥实验; min(C.x,D.x)<=max(A.x,B.x)&& min(A.y,B.y)<=max(C.y,D.y)&& min(C.y,D.y)<=max(A.y,B.y)&& Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&& // 跨立实验; Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0) // 叉乘异号表示在两侧; return true; else return false; }
22.求三角形外心
Point circumcenter(const Point &a, const Point &b, const Point &c)//返回三角形的外心 { Point ret; double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2; double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2; double d = a1*b2 - a2*b1; ret.x = a.x + (c1*b2 - c2*b1) / d; ret.y = a.y + (a1*c2 - a2*c1) / d; return ret; }
23.极角排序
double cross(point p1, point p2, point q1, point q2)//叉积计算 { return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y); } bool cmp(point a, point b) { point o; o.x = o.y = 0; return cross(o, b, o, a) < 0; //叉积判断 } sort(convex + 1, convex + cnt, cmp);//按角排序 从小到大
24.kmp算法
void getnext(int b[maxn], int next[maxm]) { int j = 0, k = -1; next[0] = -1; while (j < m - 1) {//m是字符串长度 if (k == -1 || b[j] == b[k]) { j++; k++; next[j] = k; } else k = next[k]; } } void kmp(int a[maxn], int b[maxn]) { int next[maxm]; int i = 0, j = 0; getnext(b, next); while (i < n) { if (j == -1 || a[i] == b[j]) {//母串不动,子串移动 j++; i++; } else { // i不需要回溯了 // i = i - j + 1; j = next[j]; } if (j == m) { printf("%d\n", i - m + 1);//母串的位置减去子串的长度+1 return; } } printf("-1\n"); }
kmp扩展
#include<iostream> #include<cstring> using namespace std; const int MM=100005; int next[MM],extand[MM]; char S[MM],T[MM]; void GetNext(const char *T) { int len = strlen(T),a = 0; next[0] = len; while(a < len - 1 && T[a] == T[a + 1]) a++; next[1] = a; a = 1; for(int k = 2; k < len; k ++) { int p = a + next[a] - 1,L = next[k - a]; if( (k - 1) + L >= p) { int j = (p - k + 1) > 0 ? (p - k + 1) : 0; while(k + j < len && T[k + j] == T[j]) j++; next[k] = j; a = k; } else next[k] = L; } } void GetExtand(const char *S,const char *T) { GetNext(T); int slen = strlen(S),tlen = strlen(T),a = 0; int MinLen = slen < tlen ? slen : tlen; while(a < MinLen && S[a] == T[a]) a++; extand[0] = a; a = 0; for(int k = 1; k < slen; k ++) { int p = a + extand[a] - 1, L = next[k - a]; if( (k - 1) + L >= p) { int j = (p - k + 1) > 0 ? (p - k + 1) : 0; while(k + j < slen && j < tlen && S[k + j] == T[j]) j ++; extand[k] = j; a = k; } else extand[k] = L; } } void show(const int *s,int len){ for(int i = 0; i < len; i ++) cout << s[i] << ' '; cout << endl; } int main() { while(cin >> S >> T) { GetExtand(S,T); show(next,strlen(T)); show(extand,strlen(S)); } return 0; }
25.字典树
struct Trie{ int cnt; Trie *next[maxn]; Trie(){ cnt = 0; memset(next,0,sizeof(next)); } }; Trie *root; void Insert(char *word) { Trie *tem = root; while(*word != '\0') { int x = *word - 'a'; if(tem->next[x] == NULL) tem->next[x] = new Trie; tem = tem->next[x]; tem->cnt++; word++; } } int Search(char *word) { Trie *tem = root; for(int i=0;word[i]!='\0';i++) { int x = word[i]-'a'; if(tem->next[x] == NULL) return 0; tem = tem->next[x]; } return tem->cnt; } void Delete(char *word,int t) { Trie *tem = root; for(int i=0;word[i]!='\0';i++) { int x = word[i]-'a'; tem = tem->next[x]; (tem->cnt)-=t; } for(int i=0;i<maxn;i++) tem->next[i] = NULL; } int main() { int n; char str1[50]; char str2[50]; while(scanf("%d",&n)!=EOF) { root = new Trie; while(n--) { scanf("%s %s",str1,str2); if(str1[0]=='i') Insert(str2); else if(str1[0] == 's') { if(Search(str2)) printf("Yes\n"); else printf("No\n"); } else { int t = Search(str2); if(t) Delete(str2,t); } } } return 0; }
26.AC自动机
#include<iostream> #include<cstdio> #include<cstring> #include<string> using namespace std; #define N 1000010 char str , keyword ; int head, tail; struct node { node *fail; node *next[26]; int count; node() //init { fail = NULL;//默认为空 count = 0; for(int i = 0; i < 26; ++i) next[i] = NULL; } }*q ; node *root; void insert(char *str) //建立Trie { int temp, len; node *p = root; len = strlen(str); for(int i = 0; i < len; ++i) { temp = str[i] - 'a'; if(p->next[temp] == NULL) p->next[temp] = new node(); p = p->next[temp]; } p->count++; } void build_ac() //初始化fail指针,BFS 数组模拟队列: { q[tail++] = root; while(head != tail) { node *p = q[head++]; //弹出队头 node *temp = NULL; for(int i = 0; i < 26; ++i) { if(p->next[i] != NULL) { if(p == root) //第一个元素fail必指向根 p->next[i]->fail = root; else { temp = p->fail; //失败指针 while(temp != NULL) //2种情况结束:匹配为空or找到匹配 { if(temp->next[i] != NULL) //找到匹配 { p->next[i]->fail = temp->next[i]; break; } temp = temp->fail; } if(temp == NULL) //为空则从头匹配 p->next[i]->fail = root; } q[tail++] = p->next[i]; //入队 } } } } int query() //扫描 { int index, len, result; node *p = root; //Tire入口 result = 0; len = strlen(str); for(int i = 0; i < len; ++i) { index = str[i] - 'a'; while(p->next[index] == NULL && p != root) //跳转失败指针 p = p->fail; p = p->next[index]; if(p == NULL) p = root; node *temp = p; //p不动,temp计算后缀串 while(temp != root && temp->count != -1) { result += temp->count; temp->count = -1; temp = temp->fail; } } return result; } int main() { int num; head= tail = 0; root = new node(); scanf("%d", &num); getchar(); for(int i = 0; i < num; ++i) { scanf("%s",keyword); insert(keyword); } build_ac(); scanf("%s", str); if(query()) printf("YES\n"); else printf("NO\n"); return 0; }
27.线段树
点更新
struct node{ int l,r,maxn,sum; }tree[N<<2]; void build(int m,int l,int r){ tree[m].l = l; tree[m].r = r; if(l == r){ tree[m].maxn = a[l]; tree[m].sum = a[l]; return ; } int mid = (l+r)>>1; build(m<<1,l,mid); build((m<<1)+1,mid+1,r); tree[m].maxn = max(tree[m<<1].maxn,tree[(m<<1)+1].maxn); tree[m].sum = tree[m<<1].sum + tree[(m<<1)+1].sum; } void update(int m,int a,int val){ if(tree[m].l == a && tree[m].r == a){ tree[m].maxn = val; tree[m].sum = val; return ; } int mid = (tree[m].l+tree[m].r)>>1; if(a <= mid) update(m<<1,a,val); else update((m<<1)+1,a,val); tree[m].maxn = max(tree[m<<1].maxn,tree[(m<<1)+1].maxn); tree[m].sum = tree[m<<1].sum + tree[(m<<1)+1].sum; } int query_max(int m,int l,int r){ if(l == tree[m].l && r == tree[m].r) return tree[m].maxn; //return tree[m].sum; int mid = (tree[m].l+tree[m].r)>>1; if(r <= mid) return query_max(m<<1,l,r); if(l > mid) return query_max((m<<1)+1,l,r); return max(query_max(m<<1,l,mid), query_max((m<<1)+1,mid+1,r)); //return query_sum(m<<1,l,mid) + query_sum((m<<1)+1,mid+1,r); } build(1,1,n); update(1,a,b); query(1,a,b);
区间更新
typedef long long ll; const int maxn = 100010; int t,n,q; ll anssum; struct node{ ll l,r; ll addv,sum; }tree[maxn<<2]; void maintain(int id) { if(tree[id].l >= tree[id].r) return ; tree[id].sum = tree[id<<1].sum + tree[id<<1|1].sum; } void pushdown(int id) { if(tree[id].l >= tree[id].r) return ; if(tree[id].addv){ int tmp = tree[id].addv; tree[id<<1].addv += tmp; tree[id<<1|1].addv += tmp; tree[id<<1].sum += (tree[id<<1].r - tree[id<<1].l + 1)*tmp; tree[id<<1|1].sum += (tree[id<<1|1].r - tree[id<<1|1].l + 1)*tmp; tree[id].addv = 0; } } void build(int id,ll l,ll r) { tree[id].l = l; tree[id].r = r; tree[id].addv = 0; tree[id].sum = 0; if(l==r) { tree[id].sum = 0; return ; } ll mid = (l+r)>>1; build(id<<1,l,mid); build(id<<1|1,mid+1,r); maintain(id); } void updateAdd(int id,ll l,ll r,ll val) { if(tree[id].l >= l && tree[id].r <= r) { tree[id].addv += val; tree[id].sum += (tree[id].r - tree[id].l+1)*val; return ; } pushdown(id); ll mid = (tree[id].l+tree[id].r)>>1; if(l <= mid) updateAdd(id<<1,l,r,val); if(mid < r) updateAdd(id<<1|1,l,r,val); maintain(id); } void query(int id,ll l,ll r) { if(tree[id].l >= l && tree[id].r <= r){ anssum += tree[id].sum; return ; } pushdown(id); ll mid = (tree[id].l + tree[id].r)>>1; if(l <= mid) query(id<<1,l,r); if(mid < r) query(id<<1|1,l,r); maintain(id); } int main() { scanf("%d",&t); int kase = 0 ; while(t--){ scanf("%d %d",&n,&q); build(1,1,n); int id; ll x,y; ll val; printf("Case %d:\n",++kase); while(q--){ scanf("%d",&id); if(id==0){ scanf("%lld %lld %lld",&x,&y,&val); updateAdd(1,x+1,y+1,val); } else{ scanf("%lld %lld",&x,&y); anssum = 0; query(1,x+1,y+1); printf("%lld\n",anssum); } } } return 0; }
28.中国剩余定理
int CRT(int a[],int m[],int n) { int M = 1; int ans = 0; for(int i=1; i<=n; i++) M *= m[i]; for(int i=1; i<=n; i++) { int x, y; int Mi = M / m[i]; extend_Euclid(Mi, m[i], x, y); ans = (ans + Mi * x * a[i]) % M; } if(ans < 0) ans += M; return ans; } void extend_Euclid(int a, int b, int &x, int &y) { if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b, a % b, x, y); int tmp = x; x = y; y = tmp - (a / b) * y; }
相关文章推荐
- 如何在 LibreOffice 中创建模板以实现省时高效
- 设计模式之行为型模式 - 调用行为的传递问题
- [div+css]晒晒最新制作专题推广页模板
- 2008大学生入党申请书 模板
- IMAIL多语言模板两套Outlook&Gmail模板下载
- 在PHP中使用模板的方法
- 深入解析php模板技术原理【一】
- Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
- 在ASP中不用模板生成HTML静态页直接生成.html页面
- 基于HTML模板和JSON数据的JavaScript交互(移动端)
- C#模板方法模式(Template Method Pattern)实例教程
- javascript文本模板用法实例
- 关于Asp代码与页面的分离模板技术第1/3页
- php模板原理讲解
- 需要使用php模板的朋友必看的很多个顶级PHP模板引擎比较分析
- DataGrid 动态添加模板列 实现代码
- 详解java模板和回调机制
- C++模板之特化与偏特化详解
- 使用Lua编写Web端模板引擎的实例代码分享
- vs.net2008添加模板方法