hihocoder题目
#1014 : Trie树
思路:Trie树模板题
1 #include<stdio.h> 2 #include<string.h> 3 4 typedef struct Trie 5 { 6 int count; 7 struct Trie* next[26]; 8 }Trie_Node; 9 10 Trie_Node* creat() 11 { 12 Trie_Node* node = (Trie_Node*)malloc(sizeof(Trie_Node)); 13 memset(node, 0, sizeof(node)); 14 return node; 15 } 16 17 void insert(Trie_Node* root, char* str) 18 { 19 Trie_Node* node = root; 20 char* s = str; 21 22 while (*s) 23 { 24 if (node->next[*s - 'a'] == NULL) 25 node->next[*s - 'a'] = creat(); 26 node = node->next[*s - 'a']; 27 node->count++; 28 s++; 29 } 30 } 31 32 int search(Trie_Node* root, char* str) 33 { 34 Trie_Node* node = root; 35 char* s = str; 36 37 while (*s) 38 { 39 node = node->next[*s - 'a']; 40 if (node == NULL) 41 return 0; 42 else 43 s++; 44 } 45 46 return node->count; 47 } 48 49 int main() 50 { 51 Trie_Node* root = creat(); 52 char s[15]; 53 int n, m; 54 55 scanf("%d", &n); 56 while (n--) 57 { 58 scanf("%s", s); 59 insert(root, s); 60 } 61 62 scanf("%d", &m); 63 while (m--) 64 { 65 scanf("%s", s); 66 printf("%d\n", search(root, s)); 67 } 68 69 return 0; 70 }
#1015 : KMP算法
思路:kmp模板题
1 #include <iostream> 2 #include<string> 3 4 using namespace std; 5 6 void get_next(int* p, int n, string s) 7 { 8 int i = 0; 9 int j = -1; 10 p[0] = -1; 11 12 while (i < n) 13 { 14 if (j == -1 || s[i] == s[j]) 15 { 16 i++; 17 j++; 18 p[i] = j; 19 } 20 else 21 j = p[j]; 22 } 23 } 24 25 int main() 26 { 27 int num; 28 string s; 29 string t; 30 int m, n; 31 int count; 32 33 cin >> num; 34 while (num--) 35 { 36 count = 0; 37 cin >> s >> t; 38 m = s.size(); 39 n = t.size(); 40 41 int* next = new int[m + 1]; 42 get_next(next, m, s); 43 44 int i = 0; 45 int j = 0; 46 while(i < n) 47 { 48 if (j == -1 || t[i] == s[j]) 49 { 50 i++; 51 j++; 52 } 53 else 54 j = next[j]; 55 56 if (j >= m) 57 { 58 count++; 59 j = next[j]; 60 } 61 } 62 cout << count << endl; 63 } 64 65 return 0; 66 }
改进kmp
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 5 using namespace std; 6 7 void get_next(vector<int>& p, int n, string s) 8 { 9 int i = 0; 10 int j = -1; 11 p[0] = -1; 12 13 while (i < n) 14 { 15 if (j == -1 || s[i] == s[j]) 16 { 17 i++; 18 j++; 19 if (s[i] != s[j]) 20 p[i] = j; 21 else 22 p[i] = p[j]; 23 } 24 else 25 j = p[j]; 26 } 27 } 28 29 int main() 30 { 31 int num; 32 string s; 33 string t; 34 int m, n; 35 int count; 36 37 cin >> num; 38 while (num--) 39 { 40 count = 0; 41 cin >> s >> t; 42 m = s.size(); 43 n = t.size(); 44 45 vector<int> next(m + 1, 0); 46 get_next(next, m, s); 47 48 int i = 0; 49 int j = 0; 50 while(i < n) 51 { 52 if (j == -1 || t[i] == s[j]) 53 { 54 i++; 55 j++; 56 } 57 else 58 j = next[j]; 59 60 if (j >= m) 61 { 62 count++; 63 j = next[j]; 64 } 65 } 66 cout << count << endl; 67 } 68 69 return 0; 70 }
#1032 : 最长回文子串
思路:大名鼎鼎的Manacher算法,通过空间换时间,时间复杂度:O(n)
1 #include <iostream> 2 #include <string> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cstring> 6 #include <vector> 7 8 using namespace std; 9 10 char str[2000020],s[2000020]; 11 12 void solve() 13 { 14 int len = strlen(s); 15 string r; 16 r.resize(2 * len + 2); 17 r[0] = '$'; 18 r[1] = '#'; 19 for (int i = 0; i < len; ++i) 20 { 21 r[(i + 1) << 1] = s[i]; 22 r[((i + 1) << 1) + 1] = '#'; 23 } 24 25 vector<int> p(r.size(), 0); 26 int max_len = 0; 27 int mm = 0; 28 int id = 0; 29 for (int i = 1; i < 2 * len + 2; i++) 30 { 31 if (mm > i) 32 p[i] = (mm - i < p[2 * id - i]) ? (mm - i) : (p[2 * id - i]); 33 else 34 p[i] = 1; 35 36 while (r[i - p[i]] == r[i + p[i]]) 37 p[i]++; 38 39 if (i + p[i] > mm) 40 { 41 id = i; 42 mm = i + p[i]; 43 } 44 45 if (p[i] > max_len) 46 max_len = p[i]; 47 } 48 49 printf("%d\n", max_len - 1); 50 } 51 52 int main() 53 { 54 int t; 55 56 scanf("%d", &t); 57 while (t--) 58 { 59 scanf("%s", s); 60 solve(); 61 } 62 63 return 0; 64 }
#1038 : 01背包
思路:01背包模板题
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 int main() 8 { 9 int n, m; 10 11 cin >> n >> m; 12 vector<int> need(n); 13 vector<int> value(n); 14 vector<long long> dp(m + 1, 0); 15 16 for (int i = 0; i < n; i++) 17 cin >> need[i] >> value[i]; 18 19 for (int i = 0; i < n; i++) 20 { 21 for (int j = m; j >= need[i]; j--) 22 dp[j] = max(dp[j], dp[j - need[i]] + value[i]); 23 } 24 cout << dp[m] << endl; 25 return 0; 26 }
#1040 : 矩形判断
思路:首先判断是不是四个顶点,首先必须是四边形,用set判断,然后两组对边分别平行就是平行四边形,再加一组邻边相互垂直就是矩形了
坐标判断法:平行:x1*y2 - x2*y1 = 0 垂直:x1*x2 + y1*y2 = 0
因为只有四条边,所以直接搜了
1 #include <iostream> 2 #include <string> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <set> 7 #include <vector> 8 9 using namespace std; 10 11 int main() 12 { 13 int n; 14 vector<long long> v(4); 15 pair<long long, long long> p[4]; 16 17 cin >> n; 18 for (int i = 0; i < n; i++) 19 { 20 int flag = 0; 21 int id = 0; 22 set<pair<long long, long long>> s; 23 vector<vector<long long>> line; 24 25 for (int j = 0; j < 4; j++) 26 { 27 cin >> v[0] >> v[1] >> v[2] >> v[3]; 28 line.push_back(v); 29 s.insert(make_pair(v[0], v[1])); 30 s.insert(make_pair(v[2], v[3])); 31 } 32 if (s.size() != 4) 33 cout << "NO" << endl; 34 else 35 { 36 p[0] = make_pair(line[0][2] - line[0][0], line[0][3] - line[0][1]); 37 p[1] = make_pair(line[1][2] - line[1][0], line[1][3] - line[1][1]); 38 p[2] = make_pair(line[2][2] - line[2][0], line[2][3] - line[2][1]); 39 p[3] = make_pair(line[3][2] - line[3][0], line[3][3] - line[3][1]); 40 for (int i = 1; i < 4; i++) 41 { 42 if (p[0].first * p[i].second == p[0].second * p[i].first) 43 { 44 id = i; 45 break; 46 } 47 } 48 if (id > 0) 49 { 50 if (id == 1) 51 { 52 if (p[2].first * p[3].second == p[2].second * p[3].first && p[0].first * p[2].first + p[0].second * p[2].second == 0) 53 flag = 1; 54 } 55 else if (id == 2) 56 { 57 if (p[1].first * p[3].second == p[1].second * p[3].first && p[0].first * p[1].first + p[0].second * p[1].second == 0) 58 flag = 1; 59 } 60 else 61 { 62 if (p[2].first * p[1].second == p[2].second * p[1].first && p[0].first * p[2].first + p[0].second * p[2].second == 0) 63 flag = 1; 64 } 65 66 if (flag) 67 cout << "YES" << endl; 68 else 69 cout << "NO" << endl; 70 } 71 else 72 cout << "NO" << endl; 73 } 74 } 75 return 0; 76 }
刚开始因为是乘号所以用的long long,后来发现int也能过
1 #include <iostream> 2 #include <set> 3 #include <vector> 4 5 using namespace std; 6 7 int main() 8 { 9 int n; 10 vector<int> v(4); 11 pair<int, int> p[4]; 12 13 cin >> n; 14 for (int i = 0; i < n; i++) 15 { 16 int flag = 0; 17 int id = 0; 18 set<pair<int, int>> s; 19 vector<vector<int>> line; 20 21 for (int j = 0; j < 4; j++) 22 { 23 cin >> v[0] >> v[1] >> v[2] >> v[3]; 24 line.push_back(v); 25 s.insert(make_pair(v[0], v[1])); 26 s.insert(make_pair(v[2], v[3])); 27 } 28 if (s.size() != 4) 29 cout << "NO" << endl; 30 else 31 { 32 p[0] = make_pair(line[0][2] - line[0][0], line[0][3] - line[0][1]); 33 p[1] = make_pair(line[1][2] - line[1][0], line[1][3] - line[1][1]); 34 p[2] = make_pair(line[2][2] - line[2][0], line[2][3] - line[2][1]); 35 p[3] = make_pair(line[3][2] - line[3][0], line[3][3] - line[3][1]); 36 for (int i = 1; i < 4; i++) 37 { 38 if (p[0].first * p[i].second == p[0].second * p[i].first) 39 { 40 for (int j = 1; j < 4; j++) 41 { 42 if (j == i) 43 continue; 44 45 for (int k = 1; k < 4; k++) 46 { 47 if (k == j || k == i) 48 continue; 49 50 if (p[j].first * p[k].second == p[j].second * p[k].first && p[0].first * p[j].first + p[0].second * p[j].second == 0) 51 flag = 1; 52 } 53 } 54 } 55 } 56 if (flag) 57 cout << "YES" << endl; 58 else 59 cout << "NO" << endl; 60 } 61 } 62 return 0; 63 }
#1043 : 完全背包
思路:01背包每个背包只能用一次,所以从后往前扫不会影响前边的结果,完全背包每个背包可以无限次使用,所以从前往后扫使用任意次直到装满
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 int main() 8 { 9 int n, m; 10 11 cin >> n >> m; 12 vector<int> need(n); 13 vector<int> value(n); 14 vector<long long> dp(m + 1, 0); 15 16 for (int i = 0; i < n; i++) 17 cin >> need[i] >> value[i]; 18 19 for (int i = 0; i < n; i++) 20 { 21 for (int j = need[i]; j <= m; j++) 22 dp[j] = max(dp[j], dp[j - need[i]] + value[i]); 23 } 24 cout << dp[m] << endl; 25 return 0; 26 }
#1068 : RMQ-ST算法
思路:RMQ:求区间最大/最小值,在线处理算法——ST算法
1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int N = 1000005; 10 int n, Q; 11 int rmq[N][20]; 12 int nums[N]; 13 int q[N][2]; 14 15 void RMQ_ST() 16 { 17 for (int i = 0; i < n; i++) 18 rmq[i][0] = nums[i]; 19 20 int lenj = (int)log2(n); 21 for (int j = 1; j <= lenj; j++) 22 { 23 for (int i = 0; i + (1 << j) - 1 < n; i++) 24 rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j - 1]); 25 } 26 } 27 28 void query() 29 { 30 for (int i = 0; i < Q; i++) 31 { 32 int l = q[i][0] - 1; 33 int r = q[i][1] - 1; 34 int k = (int)log2(r - l + 1); 35 printf("%d\n", min(rmq[l][k], rmq[r - (1 << k) + 1][k])); 36 } 37 } 38 39 int main() 40 { 41 scanf("%d", &n); 42 for (int i = 0; i < n; i++) 43 scanf("%d", &nums[i]); 44 scanf("%d", &Q); 45 for (int i = 0; i < Q; i++) 46 scanf("%d%d", &q[i][0], &q[i][1]); 47 48 RMQ_ST(); 49 50 query(); 51 52 return 0; 53 }
(id从1开始)
1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int N = 1000005; 10 int n, Q; 11 int rmq[N][20]; 12 int nums[N]; 13 int q[N][2]; 14 15 void RMQ_ST() 16 { 17 for (int i = 1; i <= n; i++) 18 rmq[i][0] = nums[i]; 19 20 int lenj = (int)log2(n); 21 for (int j = 1; j <= lenj; j++) 22 { 23 for (int i = 1; i + (1 << j) - 1 <= n; i++) 24 rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j - 1]); 25 } 26 } 27 28 void query() 29 { 30 for (int i = 0; i < Q; i++) 31 { 32 int l = q[i][0]; 33 int r = q[i][1]; 34 int k = (int)log2(r - l + 1); 35 printf("%d\n", min(rmq[l][k], rmq[r - (1 << k) + 1][k])); 36 } 37 } 38 39 int main() 40 { 41 scanf("%d", &n); 42 for (int i = 1; i <= n; i++) 43 scanf("%d", &nums[i]); 44 scanf("%d", &Q); 45 for (int i = 0; i < Q; i++) 46 scanf("%d%d", &q[i][0], &q[i][1]); 47 48 RMQ_ST(); 49 50 query(); 51 52 return 0; 53 }
#1070 : RMQ问题再临
思路:小数据直接暴力扫,大数据线段树
1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int N = 10005; 10 int nums[N]; 11 int n, Q; 12 13 int main() 14 { 15 int num; 16 int l, r; 17 18 scanf("%d", &n); 19 for (int i = 1; i <= n; i++) 20 scanf("%d", &nums[i]); 21 scanf("%d", &Q); 22 for (int i = 0; i < Q; i++) 23 { 24 scanf("%d%d%d", &num, &l, &r); 25 int res = nums[l]; 26 if (num == 0) 27 { 28 while (l <= r) 29 { 30 res = min(res, nums[l++]); 31 } 32 printf("%d\n", res); 33 } 34 else 35 { 36 nums[l] = r; 37 } 38 } 39 40 return 0; 41 }
#1077 : RMQ问题再临-线段树
思路:线段树经典问题:单点修改,查询区间最值
(注意读取/输出数据时要用scanf和printf)
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 5 using namespace std; 6 7 #define N 1000005 8 #define lson (id << 1) 9 #define rson ((id << 1) | 1) 10 #define mid ((l + r) >> 1) 11 int n, q; 12 int tree[4 * N]; 13 14 void push_up(int id) 15 { 16 tree[id] = min(tree[lson], tree[rson]); 17 } 18 19 void build(int id, int l, int r) 20 { 21 if (l == r) 22 { 23 scanf("%d", &tree[id]); 24 return ; 25 } 26 27 build(lson, l, mid); 28 build(rson, mid + 1, r); 29 push_up(id); 30 } 31 32 void ins(int id, int l, int r, int pos, int t) 33 { 34 if (l == r) 35 { 36 tree[id] = t; 37 return ; 38 } 39 40 if (pos <= mid) 41 ins(lson, l, mid, pos, t); 42 else 43 ins(rson, mid + 1, r, pos, t); 44 push_up(id); 45 } 46 47 int query(int id, int l, int r, int ql, int qr) 48 { 49 if (ql <= l && r <= qr) 50 return tree[id]; 51 52 int res = 99999999; 53 if (ql <= mid) 54 res = min(res, query(lson, l, mid, ql, qr)); 55 if (mid + 1 <= qr) 56 res = min(res, query(rson, mid + 1, r, ql, qr)); 57 58 return res; 59 } 60 61 int main() 62 { 63 int num; 64 int left, right; 65 66 cin >> n; 67 build(1, 1, n); 68 69 cin >> q; 70 for (int i = 0; i < q; i++) 71 { 72 scanf("%d%d%d", &num, &left, &right); 73 74 if (num == 0) 75 printf("%d\n", query(1, 1, n, left, right)); 76 else 77 ins(1, 1, n, left, right); 78 } 79 return 0; 80 }
#1089 : 最短路径·二:Floyd算法
思路:Flyod算法,从i到j的最短距离可以根据从i出发,经过任意k个节点到达j的最短距离,此时按照01背包的想法得出递推式:dp[k][i][j] = min(dp[k - 1][i][j], dp[k - 1][i][k] + dp[k - 1][k][j]) ,化简为:dp[i][j] = min(dp[i][k], dp[k][j])
(注意k一定要在外层循环)
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 int main() 8 { 9 int n, m; 10 int x, y, d; 11 12 cin >> n >> m; 13 vector<vector<int>> dis(n + 1, vector<int>(n + 1, 99999999)); 14 for (int i = 1; i <= n; i++) 15 dis[i][i] = 0; 16 17 for (int i = 1; i <= m; i++) 18 { 19 cin >> x >> y >> d; 20 if (d < dis[x][y]) 21 { 22 dis[y][x] = d; 23 dis[x][y] = d; 24 } 25 } 26 27 for (int k = 1; k <= n; k++) 28 { 29 for (int i = 1; i <= n; i++) 30 { 31 for (int j = 1; j <= n; j++) 32 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); 33 } 34 } 35 for (int i = 1; i <= n; i++) 36 { 37 for (int j = 1; j <= n; j++) 38 { 39 cout << dis[i][j] << " "; 40 } 41 cout << endl; 42 } 43 return 0; 44 }