13.树状数组
#include<cstdio> #include<cstring> #define lowerBit(x) (x&(-x)) int num[10000]; int n; void UpDate(int x,int y)//把第x个数加y { while (x <= n) { num[x] += y; x = x+lowerBit(x); } } int Query(int x)//求从1到x的和 { int sum = 0; while (x > 0) { sum += num[x]; x = x-lowerBit(x);//x&(x-1) } return sum; } int main() { scanf ("%d",&n); memset(num,0,sizeof(num)); for (int i = 1 ; i <= n ; i++) { int t; scanf ("%d",&t); UpDate(i,t); } int m; scanf ("%d",&m); while (m--) { int x,y; scanf ("%d %d",&x,&y);//看不懂 printf ("%d ",Query(y)-Query(x-1)); } return 0; }
14.线段树//看不懂
struct Node//不要左右子节点指针的做法 { int L,R; int minV,maxV; int Mid() { return (L+R)/2;//还有这操作 } }; Node tree[800010];//4倍叶子节点数量就够 void BuildTree(int root, int L, int R) { tree[root].L = L; tree[root].R = R; tree[root].minV = INF;//这是为什么?到底哪个是大的 tree[root].maxV = -INF;//那个是小的? if(L!=R) { BuildTree(2*root+1, L, (L+R)/2); BuildTree(2*root+2, (L+R)/2+1, R); } } void Insert(int root, int i, int v) //将第i个数,其值为v,插入线段树 { if(tree[root].L == tree[root].R)//成立则亦有tree[root].R==i { tree[root].minV = tree[root].maxV = v; return ; } tree[root].minV = min(tree[root].minV , v); tree[root].maxV = max(tree[root].maxV , v); if(i <= tree[root].Mid()) Insert(2*root + 1, i, v); else Insert(2*root + 2, i, v); } void Query(int root, int s, int e) //查询区间[s,e]中的最大值和最小值,如果更优就记录在全局变量里 { if( tree[root].minV >= minV && tree[root].maxV <= maxV ) return; if( tree[root].L == s && tree[root].R == e ) { minV = min( minV, tree[root].minV ); //minV = min( minV, tree[root].minV ); maxV = max( maxV, tree[root].maxV ); return ; } if( e <= tree[root].Mid() ) Query( 2*root + 1, s, e ); else if( s > tree[root].Mid() ) Query( 2*root + 2, s, e ); else { Query( 2*root + 1, s, tree[root].Mid() ); Query( 2*root + 2, tree[root].Mid() + 1, e ); } }
15.KMP
#include <stdio.h> #include <stdlib.h> #include <string.h> //S: a b a b b a b a b a d a b a b a a a b a b a a // j // T: a b a b a a a b a b a a // next :-1 0 0 1 2 3 1 1 2 3 4 5 char s[1000], t[1000]; int next[1000] = {-1, 0, 0, 1, 2, 3, 1, 1, 2, 3, 4, 5}; int Kmp(char* s, int n, char* t, int m) { int i = 0, j = 0; while(i < n) { if(j == -1 || s[i] == t[j]) { ++i; ++j; if(j == m) { return i - m + 1; } } else { j = next[j]; } } return -1; } int main() { //ababababadababaaababaa //ababaaababaa //ababcabcacbab //abc scanf("%s%s", s, t); int l1 = strlen(s); int l2 = strlen(t); printf("第一个匹配的位置%d ", Kmp(s, l1, t, l2)); return 0; } //next[i]: 0 -> i-1 最大的前缀和后缀匹配的长度 0 -> n-1 //S: a b a b b a b a b a d a b a b a a a b a b a a //T: a b a b a a a b a b a a // -1 0 0 1 2 3 1 1 2 3 4 5 //从头选择next[j]个字符和从尾向前选择next[j]个字符是相等的 // //1>, S串和T串前面这些字符是相等的 //2>, T串前面字符有next[j]前缀和后缀匹配的长度
16.二分图
这个算法的主要思想还是“递归”,通过递归腾出位置来让更多的人匹配,以达到匹配人数最大化
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int f[500+5]; //女和哪个男配对 bool fr[505][505]; //可用vector<int> d[505]代替 bool vis[505]; //标记数组,表示这个人搜索过 int k,n,m; bool find(int x) //寻找x男生,返回:能否找到人去匹配 { for (int i = 1 ; i <= m ; i++) { if (fr[x][i] && !vis[i]) { vis[i] = true; //首先标记 if (f[i] == -1) //如果该女生没有和别人匹配 { f[i] = x; //则和该男生匹配 return true; //表示匹配完成 } else if (find(f[i])) //如果该女生匹配的男生可以找到其他的女生匹配 { f[i] = x;//递归的思想 return true; } } } return false; } int main() { while (~scanf ("%d",&k) && k) { scanf ("%d %d",&n,&m); memset(f,-1,sizeof(f)); //初始化,表示没有和任何人配对 memset(fr,false,sizeof(fr)); //初始化 for (int i = 1 ; i <= k ; i++) { int x,y; scanf ("%d %d",&x,&y); fr[x][y] = true; } int ans = 0; //表示已经配对的男生数 for (int i = 1 ; i <= n ; i++) { memset(vis,false,sizeof(vis)); if (find(i)) ans++; } printf ("%d ",ans); } return 0; }
17.字典树模板
1 #include<cstdio> 2 #include<cstring> 3 #define idx(x) (x-'a') 4 struct Node 5 { 6 int v; 7 Node *next[26]; //指向某个节点,作为其子节点之一 8 void init() 9 { 10 v = 0; //当前节点有多少人公用 11 for (int i = 0 ; i < 26 ; i++) 12 next[i] = NULL; 13 } 14 }Trie[100000]; //事先把内存分配好了 15 int ant; //下一个节点要保存到的位置 16 void insert(char str[]) 17 { 18 Node *p = &Trie[0]; //现在执行到的节点 19 int l = strlen(str); 20 for (int i = 0 ; i < l ; i++) 21 { 22 if (p->next[idx(str[i])] == NULL) 23 { 24 p->next[idx(str[i])] = &Trie[ant]; 25 ant++; 26 Trie[ant].init(); //随手初始化下一个节点 27 Trie[ant-1].v = 1; 28 p = &Trie[ant-1]; 29 } 30 else 31 { 32 p->v++; 33 p = p->next[idx(str[i])]; 34 } 35 } 36 } 37 38 int Query(char str[]) //char *str 39 { 40 int length = 0; 41 Node p = Trie[0]; 42 int l = strlen(str); 43 for (int i = 0 ; i < l ; i++) 44 { 45 if (p.next[idx(str[i])] == NULL) //到此节点没有公共前缀的串了 46 { 47 break; 48 } 49 else 50 { 51 length++; 52 p = *p.next[idx(str[i])]; 53 } 54 } 55 return length; 56 } 57 58 int main() 59 { 60 int n,m; 61 char str[20]; 62 while (~scanf ("%d %d",&n,&m)) 63 { 64 ant = 1; 65 Trie[ant].init(); 66 for (int i = 1 ; i <= n ; i++) 67 { 68 scanf ("%s",str); 69 insert(str); //建树 70 } 71 for (int i = 1 ; i <= m ; i++) 72 { 73 scanf ("%s",str); //m次查询,查str的最长公共前缀 74 printf ("%d ",Query(str)); 75 } 76 } 77 return 0; 78 } 79 /* 80 3 5 81 abac 82 abcd 83 accc 84 85 a 86 ab 87 abe 88 bc 89 aca 90 91 92 */