「USACO2011 Nov Gold」解题报告

「USACO2011 Nov Gold」解题报告

T1、Above the Median

题目链接

\(Description\)

给出一个长度为 \(n \ (n \leq 10 ^ 5)\) 序列 \(\{ a_n \} \ (a_i \leq 10 ^ 9)\),问中位数大于等于 \(k\) 的区间数量。(区间里如果有偶数个数,中位数定义为偏大的那一个)

\(Solution\)

若把 \(a_i \geq k\) 的位置标为 \(1\)\(a_i < k\) 标为 \(0\),并把这个序列记为 \(b\),该序列前缀和记为 \(pre\)
则区间 \([l,r]\) 满足题意当且仅当:
\[ r - (l - 1) \leq 2 \times (pre_r - pre_{l - 1}) \]
把变量相同的放一边:
\[ r - 2 \times pre_r \leq (l - 1) - 2 \times pre_{l - 1} \]
枚举右端点,随便找个数据结构维护左边有几个满足条件的左端点。

\(Source\)

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
    int x = 0; char c = getchar(); bool f = 0;
    while (c < '0' || c > '9')
        f |= c == '-', c = getchar();
    while (c >= '0' && c <= '9')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 1e5 + 5;

int n, nn, k, a[N], pre[N];
long long res;

struct binary_index_tree {
    int a[N << 1];
    void insert(int p) { for (; p <= nn; p += (p & -p)) ++a[p]; }
    int ask(int p) { int ret = 0; for (; p; p -= (p & -p)) ret += a[p]; return ret; }
} bit;

int main() {
    //freopen("in", "r", stdin);
    n = in(), k = in(), nn = n + n;
    for (int i = 1; i <= n; ++i)
        a[i] = in();
    for (int i = 1; i <= n; ++i)
        pre[i] = pre[i - 1] + (a[i] >= k);
    bit.insert(n);
    for (int i = 1; i <= n; ++i) {
        res += bit.ask(pre[i] + pre[i] - i + n);
        bit.insert(pre[i] + pre[i] - i + n);
    }
    printf("%lld\n", res);
    return 0;
}

T2、Binary Sudoku

题目链接

\(Description\)

给出一个 \(9 \times 9\)\(01\) 矩阵,问最少修改几个数能使每行、每列以及每个九宫格中的异或和为 \(0\)

\(Solution\)

\(f_{k, i, x, y, z}\) 表示到第 \(k\) 行,其中 \(1\)\(k\) 行每一列异或和的状态为 \(i\) (一个二进制数),当前的三个宫格异或和分别是 \(x,y,z\) 的最少操作次数;
转移枚举第 \(k\) 行的操作;
注意每个九宫格的最后一行 \(x,y,z\) 都是 \(0\)

\(Source\)

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
    int x = 0; char c = getchar(); bool f = 0;
    while (c < '0' || c > '9')
        f |= c == '-', c = getchar();
    while (c >= '0' && c <= '9')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

int a[11][4], b[515][4], f[11][515][2][2][2];
char str[15];

int main() {
    //freopen("in", "r", stdin);
    for (int i = 1; i <= 9; ++i) {
        scanf(" %s", str + 1);
        for (int j = 1; j <= 9; ++j)
            a[i][0] = (a[i][0] << 1) | (str[j] == '1');
        for (int j = 0; j < 9; ++j)
            a[i][j / 3 + 1] ^= (a[i][0] >> j) & 1;
    }
    for (int i = 1; i < 512; ++i) {
        b[i][0] = b[i - (i & -i)][0] + 1;
        for (int j = 0; j < 9; ++j)
            b[i][j / 3 + 1] ^= (i >> j) & 1;
    }
    memset(f, 0x3f, sizeof(f));
    f[0][0][0][0][0] = 0;
    for (int k = 1, tmp, t1, t2, t3; k <= 9; ++k) {
        if (k % 3 == 0) {
            for (int i = 0; i < 512; ++i)
                for (int j = 0; j < 512; ++j) {
                    if (b[j ^ a[k][0]][0] & 1)
                        continue;
                    t1 = a[k][1] ^ b[j][1];
                    t2 = a[k][2] ^ b[j][2];
                    t3 = a[k][3] ^ b[j][3];
                    tmp = f[k - 1][i ^ j ^ a[k][0]][t1][t2][t3];
                    chk_min(f[k][i][0][0][0], tmp + b[j][0]);
                }
        } else {
            for (int i = 0; i < 512; ++i)
                for (int x = 0; x < 2; ++x)
                    for (int y = 0; y < 2; ++y)
                        for (int z = 0; z < 2; ++z)
                            for (int j = 0; j < 512; ++j) {
                                if (b[j ^ a[k][0]][0] & 1)
                                    continue;
                                t1 = x ^ a[k][1] ^ b[j][1];
                                t2 = y ^ a[k][2] ^ b[j][2];
                                t3 = z ^ a[k][3] ^ b[j][3];
                                tmp = f[k - 1][i ^ j ^ a[k][0]][t1][t2][t3];
                                chk_min(f[k][i][x][y][z], tmp + b[j][0]);
                            }
        }
    }
    printf("%d\n", f[9][0][0][0][0]);
    return 0;
}

T3、Cow Steeplechase

题目链接

\(Description\)

给出 \(n \ (n \leq 250)\) 平行于坐标轴的线段,选出尽量多的线段使得这些线段两两没有交点 (顶点也算) ,横的与横的,竖的与竖的线段之间保证没有交点,输出最多能选出多少条线段。
坐标均大于 \(0\),且不超过 \(10 ^ 9\)

\(Solution\)

二分图最大独立集。

\(Source\)

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
    int x = 0; char c = getchar(); bool f = 0;
    while (c < '0' || c > '9')
        f |= c == '-', c = getchar();
    while (c >= '0' && c <= '9')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 255;

struct segment {
    int x1, y1, x2, y2;
} a[N], b[N];
int n, x, y, mp[N][N], mat[N];

void prep() {
    for (int i = 1; i <= x; ++i)
        if (a[i].x1 > a[i].x2)
            std::swap(a[i].x1, a[i].x2);
    for (int i = 1; i <= y; ++i)
        if (b[i].y1 > b[i].y2)
            std::swap(b[i].y1, b[i].y2);
    for (int i = 1; i <= x; ++i) {
        for (int j = 1; j <= y; ++j) {
            if (b[j].y1 <= a[i].y1 && a[i].y2 <= b[j].y2 &&
                a[i].x1 <= b[j].x1 && b[j].x2 <= a[i].x2)
                mp[i][j] = 1;
        }
    }
}

int vis[N];
int dfs(const int u, const int tim) {
    if (vis[u] == tim)
        return 0;
    vis[u] = tim;
    for (int v = 1; v <= y; ++v) {
        if (!mp[u][v])
            continue;
        if (!mat[v] || dfs(mat[v], tim)) {
            mat[v] = u;
            return 1;
        }
    }
    return 0;
}
int hungary() {
    int ret = 0;
    for (int i = 1; i <= x; ++i)
        ret += dfs(i, i);
    return ret;
}

int main() {
    //freopen("in", "r", stdin);
    n = in();
    for (int i = 1; i <= n; ++i) {
        a[++x] = (segment){in(), in(), in(), in()};
        if (a[x].x1 == a[x].x2)
            b[++y] = a[x--];
    }
    prep();
    printf("%d\n", n - hungary());
    return 0;
}
posted @ 2019-10-10 18:21 15owzLy1 阅读(...) 评论(...) 编辑 收藏