「2019纪中集训Day2」解题报告

T1、Attack

bzoj2674

这道题时间给的比较多 (可能是以前评测机比较弱)\(O(nm)\) 就可以过。

\(Sol\) 给了分块加划分树的做法,不是很会,但是这道题可以用很多数据结构来做;
我写了整体二分+树套树 (还没调出来),整体二分+ \(cdq\) 也行,代码应该是最短的。

只给出 \(O(nm)\) 的代码:

#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 = 6e4 + 5;

struct node {
    int x, y, z;
} a[N];

int n, m, id[N], rnk[N];

inline bool cmp(const int &i, const int &j) {
    return a[i].z < a[j].z;
}

char s[11];

int main() {
//  freopen("in", "r", stdin);
    n = in(), m = in();
    for (int i = 1; i <= n; ++i)
        a[i] = (node){in(), in(), in()}, id[i] = i;
    std::sort(id + 1, id + 1 + n, cmp);
    for (int i = 1; i <= n; ++i)
        rnk[id[i]] = i;
    while (m--) {
        scanf(" %s", s);
        if (s[0] == 'S') {
            int u = in() + 1, v = in() + 1;
            std::swap(a[u].z, a[v].z);
            std::swap(id[rnk[u]], id[rnk[v]]);
            std::swap(rnk[u], rnk[v]);
        } else {
            int x = in(), y = in(), p = in(), s = in(), k = in();
            if (!k) {
                puts("It doesn't exist.");
                continue;
            }
            if (x > p)
                std::swap(x, p);
            if (y > s)
                std::swap(y, s);
            for (int i = 1; i <= n; ++i) {
                if (a[id[i]].x >= x && a[id[i]].y >= y && a[id[i]].x <= p && a[id[i]].y <= s)
                    --k;
                if (!k) {
                    printf("%d\n", a[id[i]].z);
                    break;
                }
            }
            if (k)
                puts("It doesn't exist.");
        }
    }
    return 0;
}

T2、Contra

bzoj2676

\(Sol\)
\(f[i + 1][min(j + 1,Q)][\min(k + 1, R)] += p \times f[i][j][k]\) (第 \(i +1\) 轮通过);
\(f[i + 1][j - 1][0] += (1 - p) \times f[i][j][k], (j > 1)\) (第 \(i + 1\) 轮不通过);
因为期望的线性性,可以单独计算每一轮游戏的贡献, \(ans = \sum {f[i][j][k] \times p \times \min(k + 1, R)}\),其中 \(f[i][j][k]\) 为合法状态。

因为合法状态数最多不超过 \(\frac{Q * (Q - 1)}{2} + R + 1\),所以可以矩阵优化。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef double db;
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 M = 45;
const db eps = 4e-8;

int n, r, q, s, nn;

struct matrix {
    db a[M][M];
    matrix(db t = 0) {
        memset(a, 0, sizeof(a));
        if (t > 0)
            for (int i = 1; i <= nn; ++i)
                a[i][i] = t;
    }
    inline db* operator [] (int x) {
        return a[x];
    }
    inline matrix operator * (matrix &b) const {
        matrix ret;
        for (int k = 1; k <= nn; ++k)
            for (int i = 1; i <= nn; ++i)
                for (int j = 1; j <= nn; ++j)
                    ret[i][j] += a[i][k] * b[k][j];
        return ret;
    }
} ;

matrix qpow(matrix base, int b) {
    matrix ret(1);
    for (; b; b >>= 1, base = base * base)
        if (b & 1)
            ret = ret * base;
    return ret;
}

int state[7][21], cnt;
db calc(db p) {
    matrix a(0), trans(0);
    a[1][state[q][1]] = p, a[1][state[q - 1][0]] = 1 - p, a[1][nn] = p * std::min(1, r);
    trans[nn][nn] = 1;
    for (int j = 1; j <= q; ++j) {
        for (int k = 0; k <= r; ++k) {
            if (j != q && k >= j)
                continue;
            int x = std::min(q, j + 1), y = std::min(r, k + 1);
            trans[state[j][k]][state[x][y]] = p;
            trans[state[j][k]][state[j - 1][0]] = 1 - p;
            trans[state[j][k]][nn] = p * std::min(r, k + 1);
//          printf("%lf\n", trans[state[j][k]][nn]);
        }
    }
    trans = qpow(trans, n - 1);
    a = a * trans;
    return a[1][nn];
}

int main() {
//  freopen("in", "r", stdin);
    n = in(), r = in(), q = in(), s = in();
    for (int i = 1; i <= q; ++i)
        for (int j = 0; j <= r; ++j)
            if ((i == q) || (j < i))
                state[i][j] = ++nn;
    ++nn;
    if (calc(1) - s < eps) {
        puts("Impossible.");
        return 0;
    }
    db l = 0, r = 1, mid;
    while (r - l > eps) {
        mid = (l + r) / 2;
        if (calc(mid) > s)
            r = mid;
        else
            l = mid + eps;
    }
    printf("%lf\n", l);
    return 0;
}

T3、Bomb

bzoj2675

最大值分类讨论,最小值分治即可 (也可以选择随机化分治)

转载于:https://www.cnblogs.com/15owzLy1-yiylcy/p/11295452.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值