首页 > 其他 > 详细

校内训练 2019-10-04

时间:2019-10-05 10:29:20      阅读:62      评论:0      收藏:0      [点我收藏+]

这一场的 T1T2 有点简单,大概是 D1T1 和 D1T2 的难度。

T3 的奇怪的条件看上去就没有任何想法。\(2\) 的整次幂的条件,可以暗示很多算法,比如二进制分组、倍增、分治等。但是每一种似乎都无法使用。大约比 D2T2 的难度要大一些吧。

最后 T3 的标算的想法也很妙。通过发现最大度数为 \(1\) 的点集一定可以用 \(1\) 中颜色覆盖,从而想到分治的思路。


T1. cipele

题库传送门

http://192.168.21.187/contest/32/problem/1 = http://192.168.21.187/problem/1313

http://47.100.137.146/contest/32/problem/1 = http://47.100.137.146/problem/1313

题解

排序+二分+贪心+双指针。

没什么好说的。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<ll, int> pii;

template<typename I> inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 1e5 + 7;

int n, m;
int a[N], b[N];

inline bool check(const int &mid) {
    for (int i = 1, j = 1; i <= n; ++i) {
        while (j < m && a[i] - b[j] > mid) ++j;
        if (j > m || std::abs(a[i] - b[j]) > mid) return 0;
        ++j;
    }
    return 1;
}

inline void work() {
    if (n > m) {
        std::swap(n, m);
        for (int i = 1; i <= m; ++i) std::swap(a[i], b[i]);
    }
    std::sort(a + 1, a + n + 1);
    std::sort(b + 1, b + m + 1);
    int l = 0, r = std::max(a[n] - b[1], b[m] - a[1]);
    while (l < r) {
        int mid = (l + r) >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    printf("%d\n", l);
}

inline void init() {
    read(n), read(m);
    for (int i = 1; i <= n; ++i) read(a[i]);
    for (int i = 1; i <= m; ++i) read(b[i]);
//  dbg("**********\n");
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#else
    File(cipele);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}

T2. strah

题目传送门

http://192.168.21.187/contest/32/problem/2 = http://192.168.21.187/problem/1314

http://47.100.137.146/contest/32/problem/2 = http://47.100.137.146/problem/1314

题解

首先把题目转化成所有矩形的覆盖格子总数。

我们考虑统计所有以 \((i, j)\) 为右上角的矩形的贡献。我们令 \(a_j\) 表示从 \((i, j)\) 这个点向下,有多少个适合种草莓的格子。

那么,以 \((i, j_1)\) 为左上角,\((i, j_2)\) 为右上角的矩形的最大高度为 \(\min\{a_j\mid j_1 \leq j \leq j_2 \}\)。另外,一个长度为 \(l\)最大高度为 \(h\) 的矩形,它的的总贡献是 \(\frac{h(h+1)l}{2}\)

在统计所有以 \((i, j)\) 为右上角的矩形的贡献时,可以发现对于 \(j_1 \leq j\) 的矩形,最大高度被分成了很多段,每一段的内容就是目前的后缀最小值。

显然这个可以用单调栈维护。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<ll, int> pii;

template<typename I> inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 2e3 + 7;

int n, m;
int a[N], q[N];
char s[N][N];

inline void work() {
    for (int j = 1; j <= m; ++j)
        for (int i = 1; i <= n && s[i][j]; ++i) ++a[j];
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        ll sum = 0, hs = 0;
        int tl = 0;
        for (int j = 1; j <= m; ++j) {
            while (tl && a[j] <= a[q[tl]]) sum -= (a[q[tl]] + 1ll) * a[q[tl]] / 2 * (j - q[tl] + j - 1ll - q[tl - 1]) * (q[tl] - q[tl - 1]) / 2, hs -= (a[q[tl]] + 1ll) * a[q[tl]] / 2 * (q[tl] - q[tl - 1]), --tl;
            hs += (a[j] + 1ll) * a[j] / 2 * (j - q[tl]), sum += (a[j] + 1ll) * a[j] / 2 * (1 + j - 1ll - q[tl]) * (j - q[tl] - 1) / 2, q[++tl] = j;
            sum += hs, ans += sum;
//          dbg("i = %d, j = %d, a[j] = %d, sum = %lld, hs = %lld\n", i, j, a[j], sum, hs);
        }
        
        for (int j = 1; j <= m; ++j) --a[j];
        for (int j = 1; j <= m; ++j) if (!s[i][j]) {
            a[j] = 0;
            for (int k = i + 1; k <= n && s[k][j]; ++k) ++a[j];
        }
    }
    printf("%lld\n", ans);
}

inline void init() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%s", s[i] + 1);
        for (int j = 1; j <= m; ++j) s[i][j] = s[i][j] == '.';
    }
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#else
    File(strah);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}

T3. teoreticar

题目传送门

http://192.168.21.187/contest/32/problem/3 = http://192.168.21.187/problem/1315

http://47.100.137.146/contest/32/problem/3 = http://47.100.137.146/problem/1315

题解

\(C\) 为这个二分图的所有点的最大度数

如果 \(C = 1\),很容易发现只需要 \(1\) 中颜色即可完成染色。

如果 \(C > 1\),那么我们考虑把这个二分图的边集分成两部分,每一部分的点的最大度数都不超过 \(\lceil \frac C2 \rceil\)。对于二分图中的一个环,因为是二分图,所以环长一定为偶数,又因为环中每一个点一定连接两条边,所以我们在环上间隔着分组。即第一条便分到第一组,第二条边分到第二组,第三条边分到第三组……

如果还有一些不成环的东西形成了一棵树。当然我们对于树的话可以随便分,只需要保持一个点的所有出边都被均匀地分到了两组即可。不过为了方便,我们考虑把二分图中左边的所有的度数为奇数的点向一个虚点连边,右边的度数为奇数的点向另一个虚点连边。如果虚点的度数为奇数,那么就把两个虚点之间再连一条边。这样,这个图中就全部是环了,可以直接用上面的方法分组。

这样,任何一个点的出边都被均匀地分到了两个组中。对于度数为奇数的点,由于虚边的存在,所以可能不均匀,因此分治以后的最大度数需要加上上取整符号,即 \(\lceil \frac C2 \rceil\)

从这个算法中可以看出,我们求得的答案不超过 \(2^{\lceil\log_2C\rceil}\)。又由于标准答案肯定不会小于 \(C\),所以我们求得的答案符合题意。

事实上,我们可以证明,标准答案一定恰好等于 \(C\),即二分图中最大度数。但是这个结论对于解决这个题目没有帮助,所以感兴趣的同学可以参考 EI 神仙的博客:https://blog.csdn.net/EI_Captain/article/details/89408037

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I> inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 2e5 + 7;
const int M = 5e5 + 7;

int n, nl, nr, m, tcl = 2;
int deg[N], ans[M], vis[N], bl[M << 1];

struct Edges { int x, y, id; } c[M], d1[M], d2[M];

struct Edge { int to, ne, w; } g[M << 1]; int head[N], tot;
inline void addedge(int x, int y, int z) { g[++tot].to = y, g[tot].w = z, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y, int z) { addedge(x, y, z), addedge(y, x, z); }

inline void dfs(int x, int fa = 0) {
    for fec(i, x, y) if (y != fa && !bl[g[i].w]) {
        bl[g[i].w] = tcl ^= 1;//, dbg("nxt: %d %d %d\n", x, y, tcl);
        head[x] = g[i].ne; dfs(y, x); return;
    }
}

inline void calc(int l, int r) {
    tot = vis[n + 1] = vis[n + 2] = head[n + 1] = head[n + 2] = 0;
//  memset(bl, 0, sizeof(bl));
//  memset(head, 0, sizeof(head));
//  memset(deg, 0, sizeof(deg));
    for (int i = l; i <= r; ++i) head[c[i].x] = head[c[i].y] = deg[c[i].x] = deg[c[i].y] = vis[c[i].x] = vis[c[i].y] = bl[c[i].id] = 0;
    for (int i = l; i <= r; ++i) adde(c[i].x, c[i].y, c[i].id), ++deg[c[i].x], ++deg[c[i].y];//, dbg("edges: %d %d\n", c[i].x, c[i].y);
    int mm = m, mxd = 0, dd = 0;
    for (int i = l; i <= r; ++i) {
        smax(mxd, deg[c[i].x]), smax(mxd, deg[c[i].y]);
//      if (deg[c[i].x] == mxd) dbg("*** mxd: x = %d\n", c[i].x);
//      if (deg[c[i].y] == mxd) dbg("*** mxd: y = %d\n", c[i].y);
        if (deg[c[i].x] & 1) adde(c[i].x, n + 1, ++mm), ++dd;
        if (deg[c[i].y] & 1) adde(c[i].y, n + 2, ++mm);
        deg[c[i].x] = deg[c[i].y] = 0;
    }
//  dbg("l = %d, r = %d, mxd = %d\n", l, r, mxd);
    if (dd & 1) adde(n + 1, n + 2, ++mm);
    
    if (mxd == 1) {
        ++ans[0];
        for (int i = l; i <= r; ++i) ans[c[i].id] = ans[0];
        return;
    }
    
//  memset(bl, 0, sizeof(bl));
    for (int i = m + 1; i <= mm; ++i) bl[i] = 0;
    for (int i = l; i <= r; ++i) if (!vis[c[i].x]) dfs(c[i].x);
//  dbg("******************************\n");
    int totl = 0, totr = 0, tot = l - 1;
    for (int i = l; i <= r; ++i) if (/*dbg("bl[c[%d].id] = %d\n", i, bl[c[i].id]), */bl[c[i].id] == 2) d1[++totl] = c[i]; else d2[++totr] = c[i];
    for (int i = 1; i <= totl; ++i) c[++tot] = d1[i];
    for (int i = 1; i <= totr; ++i) c[++tot] = d2[i];
    calc(l, l + totl - 1), calc(l + totl, r);
}

inline void work() {
    calc(1, m);
    printf("%d\n", ans[0]);
    for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
}

inline void init() {
    read(nl), read(nr), read(m);
    n = nl + nr;
    int x, y;
    for (int i = 1; i <= m; ++i) read(x), read(y), c[i] = (Edges){ x, y + nl, i };
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#else
    File(teoreticar);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}

校内训练 2019-10-04

原文:https://www.cnblogs.com/hankeke/p/contest20191004.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!