AtCoder Beginner Contest 147
#include <bits/stdc++.h> int main() { int a, b, c; scanf("%d%d%d", &a, &b, &c); a += b + c; if (a >= 22) puts("bust"); else puts("win"); return 0; }
#include <bits/stdc++.h> int main() { static char s[110]; scanf("%s", s); int n = strlen(s); int ans = 0; for (int i = 0; i < n / 2; i++) { if (s[i] != s[n - 1 - i]) ans++; } printf("%d\n", ans); return 0; }
暴力枚举每种组合即可
#include <bits/stdc++.h> #define pii pair<int, int> const int N = 17; int n, A[N]; std::vector<std::pii> vec[N]; bool is[N]; int get(int x) { int ans = 0; while (x) { ans++; x &= (x - 1); } return ans; } bool check() { for (int i = 0; i < n; i++) if (is[i]) { for (int j = 1; j <= A[i]; j++) { if (vec[i][j].second == 1 && !is[vec[i][j].first]) return false; if (vec[i][j].second == 0 && is[vec[i][j].first]) return false; } } return true; } int main() { scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", A + i); vec[i].resize(A[i] + 1); for (int j = 1; j <= A[i]; j++) { scanf("%d%d", &vec[i][j].first, &vec[i][j].second); vec[i][j].first--; } } int ans = 0; for (int i = 0; i < (1 << n); i++) { for (int j = 0; j < n; j++) { if (i >> j & 1) is[j] = 1; else is[j] = 0; } if (check()) ans = std::max(ans, get(i)); } printf("%d\n", ans); }
按位做即可
#include <bits/stdc++.h> #define ll long long const int MOD = 1e9 + 7; const int N = 3e5 + 7; int cnt[70][2]; ll A[N]; int main() { int n; scanf("%d", &n); int ans = 0; for (int i = 1; i <= n; i++) { scanf("%lld", A + i); for (int j = 0; j <= 60; j++) { int id = A[i] >> j & 1; id ^= 1; (ans += (1LL << j) % MOD * cnt[j][id] % MOD) %= MOD; cnt[j][A[i] >> j & 1]++; } } printf("%d\n", ans); return 0; }
$dp[i][j][k]$ 表示走到 $(i,j)$ 位置,能否出现差为 $k - 6400$ 的走法。
然后就背包,可以用 bitset 优化
#include <bits/stdc++.h> const int N = 88; const int M = 6400; int n, m, A[N][N], B[N][N]; std::bitset<M * 2 + 1> dp[N][N]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", A[i] + j); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", B[i] + j); dp[0][1].set(M); dp[1][0].set(M); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { int d = std::abs(A[i][j] - B[i][j]); dp[i][j] |= (dp[i - 1][j] << d) | (dp[i - 1][j] >> d); dp[i][j] |= (dp[i][j - 1] << d) | (dp[i][j - 1] >> d); } int ans = 1e9; for (int i = 0; i <= 2 * M; i++) if (dp[n][m].test(i)) ans = std::min(ans, std::abs(i - M)); printf("%d\n", ans); return 0; }
即求能组成多少种 $S$。
当 $D=0$ 时,如果 $X=0$,那么 $S$ 只有一种取值 $0$,否则就有 $n+1$ 种取值,$0, X, 2X, \cdots, nX$。
若 $D<0$,可以把 $X$ 和 $D$ 都乘上 $-1$,这样就只需要考虑 $D>0$ 的情况。
当 $S$ 中有 $k$ 个元素时,$S = kX + I * D$
$0 + 1 + \cdots + (k - 1) \leq I \leq (n - k) + \cdots + (n - 1)$。
相当于一条线段,然后再把这条线段左右端点都加上 $kX / D$ 的值,就变成了一个三元组 $(kX \mod D, l, r)$
对于相同的 $kX \mod D$,线段 $l, r$ 的并集就是答案了。
排序之后扫一遍就行了。