2021牛客暑期多校训练营4 个人补题记录

比赛链接:Here

1001 - Course

1002 - Sample Game

1003 - LCS

构造,

首先排除不可能的情况

  • 两个 LCS 的值减去最小的 LCS 值如果比 n 还大,那么肯定构造不出来啊(不够长

剩下就是对于公共的 min(a,b,c)a ,对应的三种情况分别赋予 b,c,d 如果还是不够 n 则赋予不同值即可

Show Code



1004 - Rebuild Tree

1005 - Tree Xor

1006 - Just a joke

讨论区有人提出

有两种操作:

  1. 删除一条边(边的数目-1)
  2. 删除个连通分量 (点的数目-k,边的数目-(k-1))

所以每次操作边和点的奇偶性都会变化,所以只需要判断边加点和的奇偶性即可。

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    int x, y;
    for (int i = 0; i < m; i++) cin >> x >> y;
    if ((n + m) & 1) puts("Alice");
    else puts("Bob");
}

在赛时队友想到了用并查集求连通块量 + 单独的点的奇偶性

const int N = 10010;
int f[N], ans;
int find(int x) {return x == f[x] ? x : f[x] = find(f[x]);}
void merge(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) f[y] = x;
    else ++ans;
}
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) f[i] = i;
    for (int i = 0, x, y; i < m; ++i) {
        cin >> x >> y;
        merge(x, y);
    }
    int cnt = 0;
    for (int i = 1; i <= n; ++i) {
        if (f[i] == i) cnt++;
    }
    cout << ((ans + cnt) % 2 == 0 ? "Bob\n" : "Alice\n");
}

1007 - Product

1008 - Convolution

1009 - Inverse Pair

对原数组处理以后求个逆序对即可

a 数组中选择合适的 bi{0,1} 来最小化逆序对数

求逆序对的方法有树状数组和归并排序,这里写归并排序简单一点

同时一定要开 long long 防止溢出

Show Code



1010 - Average

为什么连板子都没看出来啊?明明比赛前一天还复习了单调队列优化DP的题

a1...nbi...m 构成的数组形成的 n×m 的矩阵求至少长度为 x×y 的最大值子矩阵

我们要求至少长度为 x×y 的最大值子矩阵,转化过来就是求出 a1...nbi...m 中找一个最长的连续一段区间使其平均值最大。最后两者相加即可


二分答案平均值。

judge时把每一个a[i]-mid得到b[i]

在b[i]中找到一段合法的串使其权值和最大。

当最大权值和大于等于0时则mid上移。

求最大权值和用单调队列就行。(预处理b[i]的前缀和sum[i],队列中记录当前位置可选区间的最小的sum[i])

核心代码参考:Here

bool check(double x) {
    int i, l = 1, r = 0;
    for (i = 1; i <= n; i++)
        a[i] = (double)b[i] - x;
    sum[0] = 0;
    for (i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + a[i];
    for (i = 1; i <= n; i++) {
        if (i >= s) {
            while (r >= l && sum[i - s] < sum[q[r]])r--;
            q[++r] = i - s;
        }
        if (l <= r && q[l] < i - t)l++;
        if (l <= r && sum[i] - sum[q[l]] >= 0)return true;
    }
    return false;
}
int main() {
    ...
    int ans = l = -10000; r = 10000;
    while (r - l > 1e-5) {
        mid = (l + r) / 2;
        if (check(mid)) ans = l = mid;
        else r = mid;
    }
    printf("%.3lf\n", ans);
    return 0;
}

【AC Code】

Show Code



posted @   RioTian  阅读(68)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 全程不用写代码,我用AI程序员写了一个飞机大战
历史上的今天:
2020-07-31 线段树 - 多组图带你从头到尾彻底理解线段树
2020-07-31 ZOJ - 1610 区间修改+暴力单点查询
2020-07-31 什么是离散化?C++实现方法
2020-07-31 离散化/线段树 (POJ - 2528 Mayor's posters)
2020-07-31 HDU--1166--单点更新
点击右上角即可分享
微信分享提示

📖目录