CF339

C. Xenia and Weights

有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("
");
    }
}

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);
    }
}
原文地址:https://www.cnblogs.com/litstrong/p/3285099.html