A:Zero Array
题意:两种操作, 1 p v 将第p个位置的值改成v 2 查询最少的操作数使得所有数都变为0 操作为可以从原序列中选一个非0的数使得所有非0的数减去它,并且所有数不能变为负数
思路:考虑第二种操作,显然,最少的操作数肯定是不同数的个数 用map 记录,特殊注意0的存在
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 unordered_map <int, int> mp; 8 9 int t, n, q; 10 11 int arr[N]; 12 13 int main() 14 { 15 cin.tie(0); 16 cout.tie(0); 17 ios::sync_with_stdio(false); 18 cin >> t; 19 while (t--) 20 { 21 cin >> n >> q; 22 mp.clear(); 23 for (int i = 1; i <= n; ++i) 24 { 25 cin >> arr[i]; 26 mp[arr[i]]++; 27 } 28 int op, p, v; 29 while (q--) 30 { 31 cin >> op; 32 if (op == 1) 33 { 34 cin >> p >> v; 35 if (mp[arr[p]] == 1) 36 { 37 mp.erase(arr[p]); 38 } 39 else 40 { 41 mp[arr[p]]--; 42 } 43 mp[v]++; 44 arr[p] = v; 45 } 46 else 47 { 48 mp[0]++; 49 cout << mp.size() - 1 << endl; 50 } 51 } 52 } 53 return 0; 54 }
B:New Assignment
题意:给出n个人,有男生有女生,每个人有权值,进行分组,一个男的可以一组,一个女的可以一组,一男一女可以一组当且仅当他们的权值的最大公约数大于1,求最少的分组数量
思路:优先让一男一女分组,让可以一起分组的男女连边,跑二分匹配或者最大流,建图的时候注意不能够直接GCD,这样常数比较大,我们分解质因数卡卡常就可以过去
二分图匹配:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 10010 6 #define M 1000010 7 #define INF 0x3f3f3f3f 8 9 vector <int> G[N]; 10 int uN, vN; 11 int Mx[N], My[N]; 12 int dx[N], dy[N]; 13 int dis; 14 bool used[N]; 15 16 inline bool SearchP() 17 { 18 queue <int> Q; 19 dis = INF; 20 memset(dx, -1, sizeof dx); 21 memset(dy, -1, sizeof dy); 22 for (int i = 0; i < uN; ++i) 23 if (Mx[i] == -1) 24 { 25 Q.push(i); 26 dx[i] = 0; 27 } 28 while (!Q.empty()) 29 { 30 int u = Q.front(); 31 Q.pop(); 32 if (dx[u] > dis) break; 33 int sz = G[u].size(); 34 for (int i = 0; i < sz; ++i) 35 { 36 int v = G[u][i]; 37 if (dy[v] == -1) 38 { 39 dy[v] = dx[u] + 1; 40 if (My[v] == -1) dis = dy[v]; 41 else 42 { 43 dx[My[v]] = dy[v] + 1; 44 Q.push(My[v]); 45 } 46 } 47 } 48 } 49 return dis != INF; 50 } 51 52 inline bool DFS(int u) 53 { 54 int sz = G[u].size(); 55 for (int i = 0; i < sz; ++i) 56 { 57 int v = G[u][i]; 58 if (!used[v] && dy[v] == dx[u] + 1) 59 { 60 used[v] = true; 61 if (My[v] != -1 && dy[v] == dis) continue; 62 if (My[v] == -1 || DFS(My[v])) 63 { 64 My[v] = u; 65 Mx[u] = v; 66 return true; 67 } 68 } 69 } 70 return false; 71 } 72 73 inline int MaxMatch() 74 { 75 int res = 0; 76 memset(Mx, -1, sizeof Mx); 77 memset(My, -1, sizeof My); 78 while (SearchP()) 79 { 80 memset(used, false, sizeof used); 81 for (int i = 0; i < uN; ++i) 82 if (Mx[i] == -1 && DFS(i)) 83 res++; 84 } 85 return res; 86 } 87 88 int t, n; 89 90 int arr[N], brr[N]; 91 92 vector <int> pr[M], fac[M]; 93 94 inline void Init() 95 { 96 for (int i = 2; i <= 1000000; ++i) 97 if (pr[i].empty()) 98 for (int j = i; j <= 1000000; j += i) 99 pr[j].emplace_back(i); 100 } 101 102 int a[N], b[N]; 103 map <int, bool> mp; 104 105 int main() 106 { 107 Init(); 108 scanf("%d", &t); 109 while (t--) 110 { 111 scanf("%d", &n); 112 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 113 uN = 0, vN = 0; 114 char c; 115 for (int i = 1; i <= n; ++i) 116 { 117 scanf(" %c", &c); 118 if (c == 'F') 119 { 120 a[uN] = arr[i]; 121 for (int j = 0, len = pr[arr[i]].size(); j < len; ++j) 122 { 123 int x = pr[arr[i]][j]; 124 fac[x].emplace_back(uN); 125 } 126 G[uN].clear(); 127 uN++; 128 } 129 else 130 { 131 b[vN] = arr[i]; 132 vN++; 133 } 134 } 135 for (int i = 0; i < vN; ++i) 136 { 137 mp.clear(); 138 for (int j = 0, len = pr[b[i]].size(); j < len; ++j) 139 { 140 int x = pr[b[i]][j]; 141 for (int k = 0, lenn = fac[x].size(); k < lenn; ++k) 142 { 143 int id = fac[x][k]; 144 if (mp[id] == false) 145 { 146 mp[id] = true; 147 G[id].emplace_back(i); 148 } 149 } 150 } 151 } 152 printf("%d\n", n - MaxMatch()); 153 for (int i = 0; i < uN; ++i) 154 { 155 for (int j = 0, len = pr[a[i]].size(); j < len; ++j) 156 { 157 int x = pr[a[i]][j]; 158 fac[x].clear(); 159 } 160 } 161 } 162 }
最大流:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e4 + 10; 6 const int INF = 0x3f3f3f3f; 7 8 int n, m; 9 10 struct Edge { 11 int from; 12 int to; 13 int cap; 14 int flow; 15 inline Edge(){} 16 inline Edge(int from, int to, int cap, int flow) :from(from), to(to), cap(cap), flow(flow) {}; 17 }; 18 19 20 map<pair<int, int>, bool>mp; 21 vector<int>pre[1000010]; 22 vector<int>vec[1000010]; 23 int arr[maxn]; 24 int sex[maxn]; 25 vector<Edge>edge; 26 vector<int>G[maxn]; 27 int vis[maxn]; 28 int d[maxn]; 29 int cur[maxn]; 30 int S, T; 31 32 inline void init() 33 { 34 mp.clear(); 35 edge.clear(); 36 for (int i = 0; i <= n + 1; ++i) 37 { 38 G[i].clear(); 39 } 40 } 41 42 inline void addedge(int from, int to, int cap) 43 { 44 edge.push_back(Edge(from, to, cap, 0)); 45 edge.push_back(Edge(to, from, 0, 0)); 46 int len = edge.size(); 47 G[from].push_back(len - 2); 48 G[to].push_back(len - 1); 49 } 50 51 inline bool BFS() 52 { 53 memset(d, 0, sizeof d); 54 memset(vis, 0, sizeof vis); 55 queue<int>q; 56 q.push(S); 57 d[S] = 1; 58 vis[S] = 1; 59 while (!q.empty()) 60 { 61 int x = q.front(); 62 q.pop(); 63 for (auto it : G[x]) 64 { 65 Edge &e = edge[it]; 66 if (!vis[e.to] && e.cap > e.flow) 67 { 68 vis[e.to] 69 = 1; 70 d[e.to] = d[x] + 1; 71 q.push(e.to); 72 } 73 } 74 } 75 return vis[T]; 76 } 77 78 inline int DFS(int x, int a) 79 { 80 if (x == T || a == 0) return a; 81 int flow = 0; 82 int f = 0; 83 for (int &i = cur[x]; i < G[x].size(); ++i) 84 { 85 Edge &e = edge[G[x][i]]; 86 if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) 87 { 88 e.flow += f; 89 edge[G[x][i] ^ 1].flow-f; 90 flow += f; 91 a -= f; 92 if (a == 0) break; 93 } 94 } 95 return flow; 96 } 97 98 inline int dicnic() 99 { 100 int ans = 0; 101 while (BFS()) 102 { 103 memset(cur, 0, sizeof cur); 104 ans += DFS(S, INF); 105 } 106 return ans; 107 } 108 109 inline void work() 110 { 111 for (int i = 2; i <= 1000000; ++i) 112 { 113 if (pre[i].size() == 0) 114 { 115 for (int j = i; j <= 1000000; j += i) 116 { 117 pre[j].push_back(i); 118 } 119 } 120 } 121 } 122 123 int main() 124 { 125 work(); 126 int t; 127 scanf("%d", &t); 128 while (t--) 129 { 130 init(); 131 scanf("%d", &n); 132 S = 0, T = n + 1; 133 for (int i = 1; i <= n; ++i) 134 { 135 scanf("%d", &arr[i]); 136 } 137 for (int i = 1; i <= n; ++i) 138 { 139 char c; 140 scanf(" %c", &c); 141 if (c == 'F') 142 { 143 for (auto it : pre[arr[i]]) 144 { 145 vec[it].push_back(i); 146 } 147 sex[i] = 0; 148 } 149 else 150 { 151 sex[i] = 1; 152 } 153 } 154 for (int i = 1; i <= n; ++i) 155 { 156 if (sex[i] == 1) 157 { 158 for (auto j : pre[arr[i]]) 159 { 160 for (auto k : vec[j]) 161 { 162 if (mp[make_pair(i, k)] == false) 163 { 164 addedge(i, k, 1); 165 mp[make_pair(i, k)] = mp[make_pair(k, i)] = true; 166 } 167 } 168 } 169 } 170 } 171 for (int i = 1; i <= n; ++i) 172 { 173 if (sex[i] == 1) addedge(0, i, 1); 174 else if (sex[i] == 0) addedge(i, n + 1, 1); 175 } 176 int ans = n - dicnic(); 177 printf("%d\n", ans); 178 for (int i = 0; i <= n + 1; ++i) 179 { 180 for (auto x : pre[arr[i]]) 181 { 182 vec[x].clear(); 183 } 184 } 185 } 186 return 0; 187 }
C:Intersections
题意:给出两个数组,数组里面是相同的数,然后相同的数之间连边,求有多少交点,交点重叠算多个点
思路:从第二个数组开始下手,考虑到当前位置,连边,如果之前的边连的点在当前点连的目标点的后面,就会产生一个点,也就是说统计一下之前有多少个点的目标点在目前这个点的目标点后面,树状数组处理一下
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 #define ll long long 7 8 int t, n; 9 10 int a[N], b[N]; 11 int id[N]; 12 13 int arr[N]; 14 15 inline int lowbit(int x) 16 { 17 return x & (-x); 18 } 19 20 inline void update(int x, int val) 21 { 22 for (int i = x; i <= n; i += lowbit(i)) 23 arr[i] += val; 24 } 25 26 inline int sum(int x) 27 { 28 int ans = 0; 29 for (int i = x; i; i -= lowbit(i)) 30 ans += arr[i]; 31 return ans; 32 } 33 34 int main() 35 { 36 scanf("%d", &t); 37 while (t--) 38 { 39 scanf("%d", &n); 40 for (int i = 1; i <= n; ++i) 41 scanf("%d", a + i), id[a[i]] = i; 42 for (int i = 1; i <= n; ++i) 43 scanf("%d", b + i); 44 memset(arr, 0, sizeof arr); 45 ll ans = 0; 46 for (int i = 1; i <= n; ++i) 47 { 48 int index = id[b[i]]; 49 ans += sum(n) - sum(index); 50 update(index, 1); 51 } 52 printf("%lld\n", ans); 53 } 54 return 0; 55 }
D:Balloons
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, n; 6 7 int main() 8 { 9 scanf("%d", &t); 10 while (t--) 11 { 12 scanf("%d", &n); 13 int cnt = 0; 14 for (int i = 1, num; i <= n; ++i) 15 { 16 scanf("%d", &num); 17 if (num == 0) cnt ++; 18 } 19 printf("%d\n", n - cnt); 20 } 21 return 0; 22 }
E:Maximum Sum
题意:在矩阵中选取部分数,使得权值最大,其中选中的数八个方向的数均不可在选取。、
思路:注意到n很小,可以考虑二进制位表示这个数取不取以及搜索的方法来写。其中遍历每个数的时候,决定这个数能否选取主要取决于这个数的左上角,上方,右上角,左方的数字是否选取。通过一个长度为(1 << 17)的数字表示当前这个数字的左上方到左方的状态。其中第低位表示当前数字的左上方,最高位表示当前数字的左方。在搜索中每个数都有两种状态,取和不取。每次都将当前状态右移一味,去掉没有影响的数字,在添上自己的状态,从而进行下一层的搜索。注意考虑当前数字在这一行第一位和最后一位的情况。最后再添加一点剪枝。
#include<bits/stdc++.h> using namespace std; int n; int ans; int arr[20][20]; int type[17][17][1 << 17]; inline int DFS(int x, int y, int state) { if (x == n - 1 && y == n) return 0; if (y == n) return DFS(x + 1, 0, state); if (type[x][y][state] != -1) return type[x][y][state]; //not int res = DFS(x, y + 1, (state >> 1)); //do if (y == 0) { if (!(state & (1 << 1)) && !(state & (1 << 2))) res = max(res, DFS(x, y + 1, ((state >> 1) | (1 << n))) + arr[x][y]); } else if (y == n - 1) { if (!(state & 1) && !(state & (1 << 1)) && !(state & (1 << n))) res = max(res, DFS(x, y + 1, ((state >> 1) | (1 << n))) + arr[x][y]); } else { if (!(state & 1) && !(state & (1 << 1)) && !(state & (1 << 2)) && !(state & (1 << n))) res = max(res, DFS(x, y + 1, ((state >> 1) | (1 << n))) + arr[x][y]); } type[x][y][state] = res; return res; } int main() { int t; scanf("%d", &t); while (t--) { memset(type, -1, sizeof type); scanf("%d", &n); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) scanf("%d", &arr[i][j]); printf("%d\n", DFS(0, 0, 0)); } return 0; }
F:Working Time
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, n, m; 6 7 int main() 8 { 9 scanf("%d", &t); 10 while (t--) 11 { 12 scanf("%d%d", &n, &m); 13 int tot = 0; 14 int a, b, c, d; 15 for (int i = 1; i <= n; ++i) 16 { 17 scanf("%2d:%2d", &a, &b); 18 scanf("%2d:%2d", &c, &d); 19 int aa = a * 60 + b; 20 int bb = c * 60 + d; 21 tot += abs(aa - bb); 22 } 23 puts(tot >= m * 60 ? "YES" : "NO"); 24 } 25 return 0; 26 }
G:Hard Equation
留坑。
(拓展BSGS)
H:Cube
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, a; 6 7 int main() 8 { 9 scanf("%d", &t); 10 while (t--) 11 { 12 scanf("%d", &a); 13 int ans = a / 6; 14 ans = sqrt(ans); 15 printf("%d\n", ans); 16 } 17 return 0; 18 }
I:Circles
题意:给出圆心,半径,求图中阴影部分面积
思路:四个小圆面积 + 大圆面积 - 矩形面积
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 int t; 8 ll a, b, d; 9 10 int main() 11 { 12 scanf("%d", &t); 13 while (t--) 14 { 15 scanf("%lld%lld%lld", &a, &b, &d); 16 printf("%.10f\n", (d * d) * 1.0 / 2); 17 } 18 return 0; 19 }
J: Smallest Difference
水。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define N 10010 5 6 int arr[N]; 7 8 int main() 9 { 10 int t; 11 scanf("%d",&t); 12 while(t--) 13 { 14 memset(arr, 0 ,sizeof arr); 15 int n; 16 scanf("%d",&n); 17 for(int i =1;i<=n;++i) 18 { 19 int x; 20 scanf("%d",&x); 21 arr[x]++; 22 } 23 int ans = 0; 24 for(int i = 1;i <= 10000; ++i) 25 { 26 ans = max(arr[i] + arr[i + 1], ans); 27 } 28 printf("%d\n",ans); 29 } 30 return 0; 31 }
K:Citations
按题意模拟即可
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, n; 6 7 string s; 8 9 string author, title, journal, volume, number, pages, year; 10 11 inline void Init() 12 { 13 author.clear(); 14 title.clear(); 15 journal.clear(); 16 volume.clear(); 17 number.clear(); 18 pages.clear(); 19 year.clear(); 20 } 21 22 inline void work(string &ans) 23 { 24 bool flag = false; 25 for (int i = 0, len = s.size(); i < len; ++i) 26 { 27 if (s[i] == '{') 28 { 29 flag = true; 30 continue; 31 } 32 if (s[i] == '}') return; 33 if (flag == false) continue; 34 ans += s[i]; 35 } 36 return; 37 } 38 39 inline bool Find(string t) 40 { 41 if (t.size() > s.size()) return false; 42 for (int i = 0, len = t.size(); i < len; ++i) 43 { 44 if (s[i] != t[i]) return false; 45 } 46 return true; 47 } 48 49 inline void work_author() 50 { 51 bool flag = false; 52 bool fi = false; 53 int cnt = 0; 54 for (int i = 0, len = s.size(); i < len; ++i) 55 { 56 if (s[i] == '{') 57 { 58 flag = true; 59 continue; 60 } 61 if (s[i] == '}') return; 62 if (isalpha(s[i]) && flag) 63 { 64 if (fi == false) 65 { 66 if(cnt) author += ", "; 67 author += s[i];i++; 68 author += s[i]; 69 author += ". "; 70 while (s[i] != ' ') i++; 71 fi = true; 72 } 73 else 74 { 75 author += s[i]; 76 while (s[i] != ',') i++; 77 cnt++; 78 fi = false; 79 } 80 } 81 } 82 } 83 84 int main() 85 { 86 cin.tie(0); 87 cout.tie(0); 88 ios::sync_with_stdio(false); 89 cin >> t; 90 while (t--) 91 { 92 cin >> n; 93 while (n--) 94 { 95 Init(); 96 getline(cin, s); 97 while (getline(cin, s)) 98 { 99 if (s == "}") break; 100 if (Find("author")) work_author(); 101 else if (Find("title")) work(title); 102 else if (Find("journal")) work(journal); 103 else if (Find("volume")) work(volume); 104 else if (Find("number")) work(number); 105 else if (Find("year")) work(year); 106 else if (Find("pages")) work(pages); 107 else continue; 108 } 109 cout << author << ". " << title << ". " << journal << ". " << year << ";" << volume << "(" << number << "):" << pages << ".\n"; 110 } 111 } 112 }
赛后总结:
- 考虑数据中是否有特殊点会影响答案
- 模拟题请考虑更多细节
- 很多东西可以多考虑一点,比如给出的两个数,按题意是需要有大小关系,但是数据不一定保证其大小关系