CF339
14704 ワード
C. Xenia and Weights
1...10 kの分銅は、天秤の上に、左右に順番に分銅を置き、その後、左右の順番が反対側の重量よりも大きく、隣接する2回の分銅が同じではないことを要求します.
解題報告は(i,j,k)はbalance,jは最後の分銅重量,kは数歩目,次いで点(0,0)->(x,y,m)からの図論問題を示し,動的計画と等価であり,複雑度はO(w^3*m)である.
上記のアルゴリズムよりも優れたアルゴリズムを与え,iステップbalanceがjに達したときの可能なすべての分銅をdp[i][j]で表すバイナリmaskであり,複雑度はO(w^2*m)であるがw<32が要求される.
D. Xenia and Bit Operations
裸の線分の木になりました.
1...10 kの分銅は、天秤の上に、左右に順番に分銅を置き、その後、左右の順番が反対側の重量よりも大きく、隣接する2回の分銅が同じではないことを要求します.
解題報告は(i,j,k)はbalance,jは最後の分銅重量,kは数歩目,次いで点(0,0)->(x,y,m)からの図論問題を示し,動的計画と等価であり,複雑度はO(w^3*m)である.
上記のアルゴリズムよりも優れたアルゴリズムを与え,iステップbalanceがjに達したときの可能なすべての分銅をdp[i][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("
");
}
}
D. Xenia and Bit Operations
裸の線分の木になりました.
#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);
}
}