booltest(longlong k){ longlong c1 = a*k; longlong c2 = b*k; if (c1 > n) { longlong r = (c1 - n + d - 1) / d; c1 -= r*d; c2 += r*d; } if (c1 <= n && c2 <=m) returntrue; elsereturnfalse; }
intmain(){ ios::sync_with_stdio(0); cin >> n >> m >> a >> b; if (n < m) swap(n, m); if (a < b) swap(a, b); d = a - b; longlong l = 0; longlong r = n; while (l <= r) { longlong m = (l+r)/2; if (test(m)) { ans = max(ans, m); l = m+1; } else { r = m-1; } } cout << ans << endl; return0; }
int n, m; int tu[55][55]; intmain(){ cin >> n >> m; // 嵌套的 for 循环 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cout << i*j << " "; } cout << endl; } return0; }
intmain(){ int n; int ans = 0; cin >> n; for (int a = 1; a<=n; ++a) { for (int b = a; b<=n; ++b) { if (a*b%2 == 0) ans++; } } cout << ans << endl; return0; }
int t, n, v[10010], tot; intmain(){ ios::sync_with_stdio(false); cin >> t; while (t--) { cin >> n; tot = 0; for (int i = 0; i < n; ++i) { cin >> v[i]; tot += v[i]; } int cnt = 0; bool ans = false; for (int i = 0; i < n && cnt*2<tot; ++i) { cnt += v[i]; if (cnt*2 == tot) { ans = true; } } if (ans) cout << "Yes" << endl; else cout << "No" << endl; } return0; }
此题的思路如下:因为 x 最大是 2025,而如果 y 需要影响 x 的运算,只能与 x 的 bit 位是 1 的位进行操作。所以 y 如果存在,则必定小于 2048。因为 2048 的二进制 1 的 bit 位已经超过 2025 的最高位了。所以直接枚举 1~2048 之间的答案即可。
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include<bits/stdc++.h> usingnamespace std;
int ans = -1; int x; intmain(){ cin >> x; for (int i = 1; i < 2048; ++i) { if ((x & i) + (x | i) == 2025) { ans = i; break; } } cout << ans << endl; return0; }
GESP 4 级
大题核心考点
考点比较散,以下是历次考题的考点。
GESP-202306 幸运数:模拟
GESP-202309 进制转换:进制转换
GESP-202309 变长编码:位操作
GESP-202312 小杨的字典:字符串操作
GESP-202312 田忌赛马:排序,模拟
GESP-202403 相似字符串:字符串操作
GESP-202403 做题:贪心
GESP-202406 黑白方块:枚举
GESP-202406 宝箱:枚举,二分
GESP-202409 黑白方块:枚举
GESP-202409 区间排序:排序
GESP-202412 Recamán:枚举
GESP-202412 字符排序:排序
GESP-202503 荒地开垦:枚举
GESP-202503 二阶矩阵:枚举
GESP-202509 排兵布阵:枚举
GESP-202509 最长连续段:排序
其中,比较常考的考点:
枚举:考了 7 次。
排序:考了 4 次。
字符串操作:考了 2 次。
GESP 5 级
大题核心考点
待补充
GESP 202506 5级真题「奖品兑换」题解
题目描述
分析
此题首先是不能暴力枚举的,因为 n 和 m 最大情况下是 10^9,这个数据规模,暴力枚举肯定会超时。
然后我们可能想到贪心,但实际可落地的贪心的策略总是有特殊情况。
最后,假如我们可以检查一个答案是否可行,我们就可以用二分答案+判定的方法求解。
二分还有一个要求,就是答案是单调递增的。我们可以想像,随着兑换券的递增,如果限定 n 的值不变,那 m 的值肯定是递增的。所以此题符合单调递增的条件。
booltest(longlong k){ longlong c1 = a*k; longlong c2 = b*k; if (c1 > n) { longlong r = (c1 - n + d - 1) / d; c1 -= r*d; c2 += r*d; } if (c1 <= n && c2 <=m) returntrue; elsereturnfalse; }
intmain(){ ios::sync_with_stdio(0); cin >> n >> m >> a >> b; if (n < m) swap(n, m); if (a < b) swap(a, b); d = a - b; longlong l = 0; longlong r = n; while (l <= r) { longlong m = (l+r)/2; if (test(m)) { ans = max(ans, m); l = m+1; } else { r = m-1; } } cout << ans << endl; return0; }
voidadd(int idx, int val){ while (idx <= n) { b[idx] += val; idx += lowbit(idx); } }
intquery(int range){ int ret = 0; while (range > 0) { ret += b[range]; range -= lowbit(range); } return ret; }
intmain(){ ios::sync_with_stdio(false); cin >> n >> m; for (int i = 1; i <=n; ++i) { cin >> a[i]; add(i, a[i]); } for (int i = 1; i <= m; ++i) { int op, x, y; cin >> op >> x >> y; if (op == 1) { add(x, y); } else { cout << query(y) - query(x-1) << endl; } } return0; }
voidadd(int x, int y, int v){ for (int i = x; i <= n; i += lowbit(i)) { for (int j = y; j <= m; j += lowbit(j)) { c[i][j] += v; } } }
查询前缀和同样需要用循环,示例代码如下:
1 2 3 4 5 6 7 8 9
intquery(int x, int y){ int res = 0; for (int i = x; i > 0; i -= lowbit(i)) { for (int j = y; j > 0; j -= lowbit(j)) { res += c[i][j]; } } return res; }
/** * Author: Tang Qiao */ #include<bits/stdc++.h> usingnamespace std; int n, m; char tu[105][105]; int ans; int movex[8] = {0, 0, 1, -1, 1, 1, -1, -1}; int movey[8] = {1, -1, 0, 0, 1, -1, 1, -1};
voiddfs(int x, int y){ tu[x][y] = '.'; for (int i = 0; i < 8; i++) { int nx = x + movex[i]; int ny = y + movey[i]; if (nx < 0 || nx >= n || ny < 0 || ny >= m || tu[nx][ny] != 'W') continue; dfs(nx, ny); } }
intmain(){ cin >> n >> m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> tu[i][j]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (tu[i][j] == 'W') { dfs(i, j); ans++; } } } cout << ans << endl; return0; }
// 行列唯一性检查 boolfinal_check(){ set<int> row_set, col_set; for (int i = 0; i < 6; i++) { int v = 0; for (int j = 0; j < 6; ++j) { v = v * 10 + (tu[i][j] - '0'); } row_set.insert(v); } if (row_set.size() != 6) returnfalse; for (int j = 0; j < 6; ++j) { int v = 0; for (int i = 0; i < 6; ++i) { v = v * 10 + (tu[i][j] - '0'); } col_set.insert(v); } if (col_set.size() != 6) returnfalse; returntrue; }
voiddfs(int r, int c); voidtry_dfs(int r, int c){ char ch = tu[r][c]; row_cnt[r][ch - '0']++; col_cnt[c][ch - '0']++; if (check(r, c)) { int nr = r; int nc = c + 1; if (nc == 6) { nr++; nc = 0; } dfs(nr, nc); } row_cnt[r][ch - '0']--; col_cnt[c][ch - '0']--; }
voiddfs(int r, int c){ if (r == 6) { if (final_check()) { for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { cout << tu[i][j]; } } cout << endl; // 因为只有一个合法解,所以找到答案就退出 exit(0); } return; } if (mark[r][c] == 0) { tu[r][c] = '1'; try_dfs(r, c); tu[r][c] = '0'; try_dfs(r, c); } else { tu[r][c] = mark[r][c]; try_dfs(r, c); } }
// 0 - 空地 // 1 - 障碍物 int tu[6][6], n, m, t, sx, sy, ex, ey, ans;
int movex[]={1,-1,0,0}; int movey[]={0,0,-1,1};
voiddfs(int x, int y){ if (x == ex && y == ey) { ans++; return; } for (int i = 0; i < 4; ++i) { int tox = x + movex[i]; int toy = y + movey[i]; if (tox >=1 && tox<=n && toy>=1 && toy<=m && tu[tox][toy]!=1){ tu[tox][toy]=1; dfs(tox, toy); tu[tox][toy]=0; } } }
intmain(){ ios::sync_with_stdio(false); cin >> n >> m >> t; cin >> sx >> sy >> ex >> ey; while (t--) { int x, y; cin >> x >> y; tu[x][y] = 1; } tu[sx][sy] = 1; dfs(sx, sy); cout << ans << endl; return0; }
voiddfs(int pt){ if (tot == n) { cout << v[1]; for (int i = 2; i < pt; ++i) { cout << "+" << v[i]; } cout << endl; return; } for (int i = v[pt-1]; tot + i <=n && i < n ; ++i) { tot += i; v[pt] = i; dfs(pt+1); tot -= i; } }
intmain(){ ios::sync_with_stdio(false); int m, n, t, ans = 0; cin >> m >> n; vector<int> v; while (cin >> t) { if (find(v.begin(), v.end(), t) == v.end()) { // 如果不在内存中 v.push_back(t); ++ans; } if (v.size() > m) v.erase(v.begin()); } cout << ans << endl; }
boolisPrime(int a){ for (int i = 2; i*i <=a; i++) { if (a%i == 0) returnfalse; } returntrue; }
初学者在写的时候,要注意 i*i 与 a 的比较是小于等于。
质因数分解
质因数分解的方法是从 2 开始试商,如果发现能整除,就把被除数中该因数去掉,关键代码是:
1
while (N % i == 0) N /= i;
这样经过几轮下来,N 的值会变得很小,最后 N 如果不为 1,N 就是最后一个质因数。
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
vector<int> prime_facs(int N){ vector<int> result; for (int i = 2; i * i <= N; i++) { if (N % i == 0) { while (N % i == 0) N /= i; result.push_back(i); } } if (N != 1) { // 说明再经过操作之后 N 留下了一个素数 result.push_back(N); } return result; }
intgetMaxPrime(int v){ int ret = 0; for (int i = 2; i*i <= v; i++) { if (v%i == 0){ ret = max(ret, i); while (v%i == 0) v/=i; // 把 v 的值缩小 } } ret = max(ret, v); return ret; }
intmain(){ cin >> n >> b; for (int i = 1; i <=n; ++i) { int t = getMaxPrime(i); if (t <= b) ans++; } cout << ans << endl; return0; }
longlongdi(longlong a, longlong L){ if (debug) { // 可用 debug 查看坐标变化过程 cout << "test a = " << a << ", L = " << L << endl; } if (a <= n) { return a; } else { // 如果 a 的位置在右半侧,则调整到左半侧 if (a > L/2) { if (a == L/2 + 1) a = L/2; else a = a - L/2 - 1; } returndi(a, L/2); } }
intmain(){ cin >> s >> a; n = s.length();
// 求出开始往回递归时,字符串拼起来的长度 L longlong L = n; while (L < a) L *= 2;
// 寻找 L 这个长度下,第 a 个字符相当于哪个位置 int ans = di(a, L); cout << s[ans-1] << endl; return0; }
intmain(){ cin >> n; for (int i = 0; i < n; ++i) { v[i] = i+1; } do { for (int i = 0; i < n; ++i) { printf("%5d", v[i]); } printf("\n"); } while (next_permutation(v, v+n)); return0; }
intmain(){ cin >> n >> r; for (int i = r; i < n; ++i) { v[i] = 1; } do { for (int i = 0; i < n; ++i) { if (v[i] == 0) printf("%3d", i+1); } printf("\n"); } while (next_permutation(v, v+n)); return0; }
intmain(){ int n, m; cin >> n >> m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { char ch; cin >> ch; cnt[i][ch]++; } } int ans = INT_MAX; // 枚举蓝色行的起止 for (int i = 1; i < n; ++i) { for (int j = i; j < n-1; ++j) { int cost = 0; for (int k = 0; k < i; ++k) cost += m - cnt[k]['W']; for (int k = i; k <= j; ++k) cost += m - cnt[k]['B']; for (int k = j+1; k < n; ++k) cost += m - cnt[k]['R']; ans = min(ans, cost); } } cout << ans << endl; return0; }
boolcheck(int x, int y, int dx, int dy){ int nx = x, ny = y; for (int i = 0; i < k; i++) { if (nx >= n || ny >= m) returnfalse; if (tu[nx][ny] == '#') returnfalse; nx += dx; ny += dy; } returntrue; }
intmain(){ ios::sync_with_stdio(false); cin >> n >> m >> k; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> tu[i][j]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (check(i, j, 1, 0)) ans++; if (check(i, j, 0, 1)) ans++; } } if (k == 1) ans /= 2; cout << ans << endl; return0; }
unordered_map<int, int> cnt; int n, x, maxv; longlong ans;
// 从 a 个数中选 2 个数的组合数 longlongC(longlong a){ return a * (a - 1) / 2; }
intmain(){ ios::sync_with_stdio(false); cin >> n; for (int i = 0; i < n; i++) { cin >> x; cnt[x]++; maxv = max(maxv, x); } for (int a = 1; a <= maxv; a++) { for (int b = a; b <= maxv; b++) { if (a == b && cnt[a] < 2) continue; int c = a + b; if (cnt[c] >= 2) { longlong base = C(cnt[c]) % MOD; if (a == b) base = base * C(cnt[a]) % MOD; else base = base * ((cnt[a] * cnt[b]) % MOD) % MOD; ans = (ans + base) % MOD; } } } cout << ans << endl; return0; }
string add(string a, string b){ int len_a = a.length(); int len_b = b.length(); int len_max = max(len_a, len_b); int carry = 0; string ret = ""; for (int i = 0; i < len_max; i++) { int num_a = i < len_a ? a[len_a - i - 1] - '0' : 0; int num_b = i < len_b ? b[len_b - i - 1] - '0' : 0; int sum = num_a + num_b + carry; ret = to_string(sum % 10) + ret; carry = sum / 10; } if (carry > 0) ret = to_string(carry) + ret; return ret; }
string dfs(int n, int m){ if (n > m) return"0"; if (n == m) return"1"; if (record[n][m] != "") return record[n][m]; return record[n][m] = add(dfs(n+1, m), dfs(n+2, m)); }
intmain(){ int n, m; cin >> n >> m; cout << dfs(n, m) << endl; return0; }