A|B
反思:这个题目分类讨论没有到位,我只是讨论了首位为零的情况,其他位为零的情况没有考虑到。
题目思路:
将题目意思抽象出来,就是求1的所有符合条件1的摆放位置。
代码
#include<bits/stdc++.h> using namespace std; int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { int a, x, ans = 0; scanf("%d%d", &a, &x); for (int bit = (1 >= 1) { if (!(x & bit)) continue; int cnt = 0; for (int i = (bit >> 1); i; i >>= 1) if (!(i & a)) cnt++; //第i位的取值为0,那么0~i-1位的取值的所有可能情况 ans += (1 << cnt); if (bit & a) break; // 第i个位置不能取1,即后面没有需要讨论的情况了,结束取值。 } if ((a | x) == a + x) ans++; //循环中是没有考虑x的,所以将x的取值放进去。 printf("%d\n", ans - 1); //答案中是大于1,并不存在所有都是0的情况 } return 0; }
A + B
直接暴力模拟即可
#include<bits/stdc++.h> using namespace std; #define _for(i, a, b) for (int i = (a); i < (b); ++i) const int N = 510, M = 6; char g[M][N]; int get_num(int x) { if (g[0][x] == '.' && g[0][x + 1] == '.' && g[0][x + 2] == '.') return 10; if (g[0][x] == '#' && g[0][x + 1] == '.' && g[0][x + 2] == '#') return 4; if (g[0][x] == '.' && g[0][x + 1] == '.' && g[0][x + 2] == '#') return 1; if (g[2][x] == '#' && g[2][x + 1] == '.' && g[2][x + 2] == '#') { if (g[4][x] == '#' && g[4][x + 1] == '#' && g[4][x + 2] == '#') return 0; return 7; } if (g[3][x] == '#' && g[3][x + 1] == '.' && g[3][x + 2] == '.') return 2; if (g[1][x] == '.' && g[1][x + 1] == '.' && g[1][x + 2] == '#') return 3; if (g[1][x] == '#' && g[1][x + 1] == '.' && g[1][x + 2] == '.') { if (g[3][x] == '.') return 5; return 6; } if (g[3][x] == '.') return 9; return 8; } void put(int x, int l) { char s[5][4] = { "###", "#.#", "#.#", "#.#", "###" }; if (x) { switch (x) { case 1: strcpy(s[0], "..#"); strcpy(s[1], "..#"); strcpy(s[2], "..#"); strcpy(s[3], "..#"); strcpy(s[4], "..#"); break; case 2: strcpy(s[0], "###"); strcpy(s[1], "..#"); strcpy(s[2], "###"); strcpy(s[3], "#.."); strcpy(s[4], "###"); break; case 3: strcpy(s[0], "###"); strcpy(s[1], "..#"); strcpy(s[2], "###"); strcpy(s[3], "..#"); strcpy(s[4], "###"); break; case 4: strcpy(s[0], "#.#"); strcpy(s[1], "#.#"); strcpy(s[2], "###"); strcpy(s[3], "..#"); strcpy(s[4], "..#"); break; case 5: strcpy(s[0], "###"); strcpy(s[1], "#.."); strcpy(s[2], "###"); strcpy(s[3], "..#"); strcpy(s[4], "###"); break; case 6: strcpy(s[0], "###"); strcpy(s[1], "#.."); strcpy(s[2], "###"); strcpy(s[3], "#.#"); strcpy(s[4], "###"); break; case 7: strcpy(s[0], "###"); strcpy(s[1], "#.#"); strcpy(s[2], "#.#"); strcpy(s[3], "..#"); strcpy(s[4], "..#"); break; case 8: strcpy(s[0], "###"); strcpy(s[1], "#.#"); strcpy(s[2], "###"); strcpy(s[3], "#.#"); strcpy(s[4], "###"); break; case 9: strcpy(s[0], "###"); strcpy(s[1], "#.#"); strcpy(s[2], "###"); strcpy(s[3], "..#"); strcpy(s[4], "###"); break; } } printf("%s", s[l]); } void print(int x) { vector v; while(x) { v.push_back(x % 10); x /= 10; } _for(i, 0, 5) for (int j = v.size() - 1; ~j; --j) put(v[j], i), printf("%s", j ? "." : "\n"); } int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); _for(kase, 0, T) { if (kase) puts(""); memset(g, 0, sizeof g); _for(i, 0, 5) scanf("%s", g[i]); int n = strlen(g[0]), t = 0; int sum = 0, ans = 0; while(t < n) { switch (get_num(t)) { case 0: sum = sum * 10; break; case 1: sum = sum * 10 + 1; break; case 2: sum = sum * 10 + 2; break; case 3: sum = sum * 10 + 3; break; case 4: sum = sum * 10 + 4; break; case 5: sum = sum * 10 + 5; break; case 6: sum = sum * 10 + 6; break; case 7: sum = sum * 10 + 7; break; case 8: sum = sum * 10 + 8; break; case 9: sum = sum * 10 + 9; break; default: ans += sum; sum = 0; break; } t += 4; } ans += sum; print(ans); } return 0; }
图像存储
这个题目非常简单,直接bfs加判重即可。
#include<bits/stdc++.h> using namespace std; #define _for(i, a, b) for(int i = (a); i < (b); ++i) typedef pair PII; typedef vector CELL; set shapes; const int N = 10100; int g[N][N], n, m, dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1}; void bfs(PII pos) { CELL cell; cell.push_back(pos); queue q; q.push(pos); int min_x = pos.first, min_y = pos.second; while(!q.empty()) { PII t = q.front(); q.pop(); _for (i, 0, 4) { int x = t.first + dx[i], y = t.second + dy[i]; if (0 <= x && x < n && 0 <= y && y < m && g[x][y]) { g[x][y] = 0; q.push({ x, y }); cell.push_back({ x, y }); min_x = min(x, min_x); min_y = min(y, min_y); } } } int sz = cell.size(); _for(i, 0, sz) cell[i].first -= min_x, cell[i].second -= min_y; if (!shapes.count(cell)) shapes.insert(cell); } int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif while (scanf("%d%d", &n, &m) == 2 && n && m) { shapes.clear(); _for(i, 0, n) _for(j, 0, m) scanf("%1d", &g[i][j]); int cnt = 0; _for (i, 0, n) _for (j, 0, m) if (g[i][j]) bfs({ i, j }), cnt++; printf("%d %d\n", cnt, shapes.size()); } return 0; }
坐标计数
这个题目我打表验算发现所有的点都可以在有限次变成(0, 0), 所以答案直接是区域中的所有点数。
#include <bits/stdc++.h> typedef long long LL; using namespace std; int main() { int T; scanf("%d", &T); while (T--) { LL x1, y1, x2, y2; scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2); printf("%lld\n", (x2 - x1 + 1) * (y2 - y1 + 1)); } return 0; }
解方程
所以这个题就是求 a * b 的约数个数。
模板题
#include<bits/stdc++.h> #include<unordered_map> using namespace std; unordered_map primes; typedef long long LL; int n; int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { primes.clear(); LL a, b; scanf("%lld%lld", &a, &b); LL x = a * b; for (int i = 2; i <= x / i; ++i) while (x % i == 0) { x /= i; primes[i]++; } if (x > 1) primes[x]++; LL res = 1; for (auto i : primes) res = res * (i.second + 1); cout << res << endl; } return 0; }
消减整数
定义: 函数s(n)为计算前n项和。
我们根据题意写表达式的时候可以发现:
第一次 : n - f(k) = m
第二次 : m + [ n - f(k) ] = 2m
第三次: 当 2m + n >= f(k + 1)
时 =》 2m + [ n - f(k) ] - (k + 1) = w
以此类推:
第x次时: xm - a(k + 1) = 0
我们需要得到x,那么只要取m
和 (k + 1)
的最大公约数再除以m
便得到了x
x = lcm(m, k + 1) / m
因为:lcm(a, b) = a * b / gcd(a, b)
所以得到 :x = (k + 1) / gcd(m, k + 1)
代码
#include<bits/stdc++.h> using namespace std; typedef long long LL; int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } inline LL S(int n) { return 1LL * n * (n + 1) >> 1; } int cal(int n) { // 取最右边符合条件的数值。 int l = 1, r = n; while (l < r) { int m = l + r + 1 >> 1; if (S(m) <= n) l = m; else r = m - 1; } return l; } int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { int n; scanf("%d", &n); int k = cal(n); int m = n - S(k++); if (!m) puts("1"); else printf("%d\n", k / gcd(m, k)); } return 0; }
简单题的逆袭
这个题目没想到直接这样做就出来了,当时比赛的时候没有想出来,题目还是看少了啊。
值得注意的是这个题目的特殊值。
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL cal(LL x, LL y) { if (x <= 1 || y == 0) return -1; LL ans = 0; while (y >= x) y /= x, ans++; return ans; } int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { LL x, y; scanf("%lld%lld", &x, &y); printf("%lld\n", cal(x, y)); } return 0; }
对称之美
两边对称判断即可。
#include<bits/stdc++.h> using namespace std; const int N = 110; char s[N][N]; int cunt[30], n; bool judge(int i) { memset(cunt, 0, sizeof cunt); int sz = strlen(s[i]); for (int j = 0; j < sz; ++j) cunt[s[i][j] - 'a']++; sz = strlen(s[n - i - 1]); bool flag = false; for (int j = 0; j < sz; ++j) if (cunt[s[n - i - 1][j] - 'a']) return true; return false; } int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { memset(s, 0, sizeof s); scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%s", s[i]); bool ans = true; for (int i = 0; i <= n / 2; ++i) if (!judge(i)) { ans = false; break; } if (ans) puts("Yes"); else puts("No"); } return 0; }
非对称之美
直接判断是否是回文串,如果不是那么直接返回长度,是的话,那么就是长度减一,因为去掉头或尾他必定不是回文串了(出除开全是相同字符的字符串)。
所以还要特判一下全是相同字符的字符串,输出0。
#include<bits/stdc++.h> using namespace std; bool is_Same(string s) { char c = s[0]; for (const auto& p : s) if (c != p) return false; return true; } int main() { string s; cin >> s; if (is_Same(s)) { puts("0"); return 0; } string t = s; reverse(t.begin(), t.end()); cout << s.size() - (t == s) << endl; return 0; }
排列算式
贪心算法
先总和的加起来,如果总和都不符合条件的话输出NO
再处理 -3的情况,依次用一个+3、两个2,一个-1、一个2一个1、三个1中和为0,还存在-3的话输出NO
再处理3的情况,依次用两个-2,一个1、一个-2一个-1、三个-1中和为0,如果3的个数大于1的话输出NO
顺利到这一步了输出YES。
采用了排除法,将NO的情况排除了,剩下的就是YES的情况了,
#include<bits/stdc++.h> using namespace std; #define _for(i, a, b) for (int i = (a); i < (b); ++i) const int N = 10; int a[N], n; bool judge(){ while (a[0]) { if (a[6]) a[6]--, a[0]--; else if (a[5] > 1 && a[2]) a[5] -= 2, a[2]--, a[0]--; else if (a[4] && a[5]) a[5] --, a[4]--, a[0]--; else if (a[4] > 2) a[4] -= 3, a[0]--; else return false; } while (a[6] > 1) { if (a[1] > 1 && a[4]) a[1] -= 2, a[4]--, a[6]--; else if (a[1] && a[2]) a[1]--, a[2]--, a[6]--; else if (a[2] > 2) a[2] -= 3, a[6]--; else return false; } return true; } int main() { #ifdef LOCAL freopen("data.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { memset(a, 0, sizeof a); char s[5]; scanf("%d", &n); int sum = 0; _for(i, 0, n) { scanf("%s", s); int x = s[1] - '0'; if (*s == '-') x = -x; sum += x; a[x + 3]++; } if (sum 3 || !judge()) puts("No"); else puts("Yes"); } return 0; }
总结
这次比赛是我寒假的第一场比赛,也是正式的第一场比赛,比赛还是打少了,没有时间没有分配的过来,首先得要保证每个题都看了一眼,目前的想法是每个题先去看一遍,仔细理解题意,将思路写在纸上,整个看完之后挑选出最适合先做的题目出来做,先把自己能AC题目拿到手。此次比赛数学和推理题较多,代码不怎么长,确实比较好玩。
全部评论
(1) 回帖