有1...10k的砝码,在天枰上,左右轮流放置砝码,要求之后左右轮流比另一侧重量要大,要求相邻两次砝码不能相同。
解题报告给出(i,j,k)表示balance,j表示最后一次的砝码重量,k表示第几步,然后表示从点(0,0,0)->(x,y,m)的图论问题,跟动态规划是等价的,复杂度是O(w^3*m)。
我给出了一个比上述算法更优的一个算法,做法是用dp[i][j]表示第i步balance达到j时的所有可能的砝码情况的二进制mask,复杂度是O(w^2*m),但要求w<32。
#include <cstdio> #include <vector> #include <cstring> #include <iostream> using namespace std; int dp[1005][25]; char w[15]; int main() { int m; scanf("%s%d", w, &m); memset(dp, 0, sizeof(dp)); dp[0][10] = 1; for (int i = 1; i <= m; i++) { for (int j = 0; j <= 20; j++) { if (dp[i - 1][j] > 0) { for (int k = 1; k <= 10; k++) if (w[k - 1] == '1') { if (dp[i - 1][j] ^ (1 << k)) { if (j >= 10 && j - k < 10) { dp[i][j - k] |= (1 << k); } else if (j < 10 && j + k > 10) { dp[i][j + k] |= (1 << k); } } } } } } int ans_j = -1; for (int j = 0; j <= 20; j++) if (dp[m][j] > 0) ans_j = j; if (ans_j == -1) { printf("NO "); } else { printf("YES "); int i = m; vector<int> ans; int last = 0; while (i > 0) { for (int j = 1; j <= 10; j++) { if (dp[i][ans_j] & (1 << j)) { if (j == last) continue; ans.push_back(j); if (ans_j >= 10) ans_j -= j; else ans_j += j; last = j; break; } } i--; } for (i = ans.size() - 1; i >= 0; i--) { printf("%d ", ans[i]); } printf(" "); } }
很裸的一个线段树了。
#include <cstdio> #include <iostream> using namespace std; const int MAXN = 1 << 17; int num[MAXN]; class SegNode { public: int L, R; int level, sum; } node[MAXN * 4]; class SegTree { public: void build(int r, int L, int R) { node[r].L = L; node[r].R = R; if (L == R) { // leaf node[r].level = 0; node[r].sum = num[L]; } else { // non leaf int M = (L + R) / 2; build(2 * r, L, M); build(2 * r + 1, M + 1, R); node[r].level = node[2 * r].level + 1; if (node[r].level & 1) { node[r].sum = node[2 * r].sum | node[2 * r + 1].sum; } else { node[r].sum = node[2 * r].sum ^ node[2 * r + 1].sum; } } } void update(int r, int p, int b) { if (node[r].L == node[r].R) { node[r].sum = b; } else { if (p <= node[2 * r].R) { // left update(2 * r, p, b); } else if (p >= node[2 * r + 1].L) { // right update(2 * r + 1, p, b); } if (node[r].level & 1) { node[r].sum = node[2 * r].sum | node[2 * r + 1].sum; } else { node[r].sum = node[2 * r].sum ^ node[2 * r + 1].sum; } } } } tree; int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= (1 << n); i++) { scanf("%d", &num[i]); } tree.build(1, 1, 1 << n); for (int i = 0; i < m; i++) { int p, b; scanf("%d%d", &p, &b); tree.update(1, p, b); printf("%d ", node[1].sum); } }