首页 > 其他分享 >2024牛客暑期多校训练营2

2024牛客暑期多校训练营2

时间:2024-08-10 10:27:25浏览次数:10  
标签:int max ++ 多校 cin 2024 牛客 mp dp

A.Floor Tiles

恶心构造,本来构造的方法没有错,因为不小心修改了第一块砖的位置,导致一直过不去,没注意,倒了
思路:先把最多曲线的构造出来,就是类似于 B A B A B A BABABA BABABA或者 A B A B A B ABABAB ABABAB的去构造,具体是哪一种形式取决于第一块瓷砖是 A A A还是 B B B,如果第一块为 A A A并且 x x x y y y奇偶性一样就是 A B A B A B ABABAB ABABAB这种, 否则 B A B A B A BABABA BABABA,如果第一块为 B B B并且 x x x y y y奇偶性一样就是 B A B A B A BABABA BABABA这种, 否则 A B A B A B ABABAB ABABAB,如图在这里插入图片描述
在这里插入图片描述

红色部分就是旋转九十度以后会减少曲线的数量,每旋转一个就减少一条,所以我们构造出来以后,直接去计算红色部分的数量加上 n + m n + m n+m就是最多的曲线数,最少是 n + m n + m n+m,先把无解的情况判断了,在把需要减少的曲线数量算出来,记得不要修改题目所给地砖

void solve() {
    int n, m, k; cin >> n >> m >> k;
    int x, y; char t; cin >> x >> y >> t;
    vector g(n + 1, vector<char>(m + 1));
    if (t == 'A') {
        if ((x & 1) == (y & 1)) g[1][1] = 'A';
        else g[1][1] = 'B';
    } else {
        if ((x & 1) == (y & 1)) g[1][1] = 'B';
        else g[1][1] = 'A';
    }
    for (int i = 2; i <= m; i ++) {
        if (g[1][i - 1] == 'A') g[1][i] = 'B';
        else g[1][i] = 'A';
    }
    for (int i = 2; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            if (g[i - 1][j] == 'A') g[i][j] = 'B';
            else g[i][j] = 'A';
        }
    }
    int smx = n + m, smn = n + m;
    for (int i = 2; i <= n; i ++) {
        for (int j = 1; j < m; j ++) {
            if (g[i][j] == 'B') {
                smx ++;
            }
        }
    }
    if (k < smn || k > smx) {
        cout << "No\n";
        return ;
    }
    int cnt = smx - k;
    if (t == 'A') {
        for (int i = 2; i <= n && cnt > 0; i ++) {
            for (int j = 1; j < m && cnt > 0; j ++) {
                if (g[i][j] == 'B') {
                    g[i][j] = 'A';
                    cnt --;
                }
            }
        }
    } else {
        for (int i = 2; i <= n && cnt > 0; i ++) {
            for (int j = 2; j <= m && cnt > 0; j ++) {
                if (g[i][j] == 'A') {
                    g[i][j] = 'B';
                    cnt --;
                }
            }
        }
    }
    cout << "Yes\n";
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            cout << g[i][j];
        }
        cout << '\n';
    }
}

B.MST

思路:根号分治,小于等于 n \sqrt{n} n ​的直接 O ( n 2 ) O(n^2) O(n2)把需要的边选出来做克鲁斯卡尔,否则直接对所有的边做克鲁斯卡尔

struct S {
    int u, v, w;

};
vector<S> val;
map<array<int, 2>, int> g;
int n, m, q;
int fa[N];

int find(int x) {
    if (fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}

void merge(int a, int b) {
    int pa = find(a), pb = find(b);
    fa[pa] = pb;
}

void solve() {
    cin >> n >> m >> q;
    val.resize(m + 1);
    for (int i = 1; i <= m; i ++) {
        int a, b, c; cin >> a >> b >> c;
        val[i] = {a, b, c};
        g[ {a, b}] = c;
        g[ {b, a}] = c;
    }
    sort(val.begin() + 1, val.end(), [&](S a, S b) {
        return a.w < b.w;
    });
    while (q --) {
        int k; cin >> k;
        vector<int> node(k + 1), query(n + 1);
        for (int i = 1; i <= k; i ++) {
            cin >> node[i];
            fa[node[i]] = node[i];
            query[node[i]] = 1;
        }
        vector<S> edge;
        int cnt = 0, sum = 0;
        if (k < 1000) {
            for (int i = 1; i <= k; i ++) {
                for (int j = i + 1; j <= k; j ++) {
                    if (i == j) continue;
                    int u = node[i], v = node[j];
                    if (g.count({u, v})) {
                        edge.push_back({u, v, g[{u, v}]});
                    }
                }
            }
            sort(edge.begin(), edge.end(), [&](S a, S b) {
                return a.w < b.w;
            });
            for (int i = 0; i < edge.size(); i ++) {
                auto [u, v, w] = edge[i];
                int pu = find(u), pv = find(v);
                if (pu != pv) {
                    cnt ++;
                    sum += w;
                    merge(u, v);
                }
            }
            if (cnt < k - 1) cout << -1 << '\n';
            else cout << sum << '\n';
        } else {
            for (int i = 1; i <= m; i ++) {
                auto [u, v, w] = val[i];
                int pu = find(u), pv = find(v);
                if (pu != pv && query[u] && query[v]) {
                    cnt ++;
                    sum += w;
                    merge(u, v);
                }
            }
            if (cnt < k - 1) cout << -1 << '\n';
            else cout << sum << '\n';
        }
    }
}

C.Red Walking on Grid

思路:直接 d p dp dp, d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1]在第 i i i走第一行和第二行的最大步数,优先让左边的先转移,在转移上下的,去 m a x max max即可

void solve() {
    int n; cin >> n;
    string s1, s2; cin >> s1 >> s2;
    vector<array<int, 2>> dp(n + 1);
    int ans = 0;
    if (s1[0] == s2[0] && s1[0] == 'R') {
        dp[0][0] = dp[0][1] = 1, ans = 1;
    }
    for (int i = 1; i < s1.size(); i++) {
        if (s1[i] == 'R' && s1[i - 1] == 'R') {
            dp[i][0] = max(dp[i - 1][0] + 1, dp[i][0]);
        }
        if (s2[i] == 'R' && s2[i - 1] == 'R') {
            dp[i][1] = max(dp[i][1], dp[i - 1][1] + 1);
        }
        if (s1[i] == s2[i] && s1[i] == 'R') {
            int t0 = dp[i][0], t1 = dp[i][1];
            dp[i][0] = max(dp[i][0], t1 + 1);
            dp[i][1] = max(dp[i][1], t0 + 1);
        }
        ans = max(ans, max(dp[i][1], dp[i][0]));
    }
    cout << ans << '\n';
}

E.GCD VS XOR

思路:取二进制下从低位开始的第一个 1 1 1的位置和 n n n做 g c d gcd gcd即可,二的整次幂没有答案

void solve() {
    int n; cin >> n;
    for (int i = 0; i < 64; i ++) {
        if (n >> i & 1) {
            int x = (1ll << i);
            if (x != n) {
                cout << (n ^ x) << '\n';
                return ;
            }
        }
    }
    cout << -1 << '\n';
}

H.Instructions Substring

思路:首先特判目标点在 0 , 0 {0, 0} 0,0的情况,答案就是 n ⋅ ( n + 1 ) 2 \frac{n \cdot (n + 1)}{2} 2n⋅(n+1)​,剩下的情况我一边遍历一边记录在这个位置我的坐标偏移到了那个位置,我把和目标点的位置差多少算出来,而这个差值我要让我减去前缀的贡献,记得要把这个前缀清零不然后续会重复计算

void solve() {
    int n, x, y; cin >> n >> x >> y;
    string s; cin >> s;
    int X = 0, Y = 0;
    map<pair<int, int>, int> mp;
    if (x == 0 && y == 0) {
        cout << n * (n + 1) / 2 << '\n';
        return ;
    }
    int ans = 0;
    mp[ {0, 0}] ++;
    for (int i = 0; i < n; i ++) {
        if (s[i] == 'A') X --;
        else if (s[i] == 'D') X ++;
        else if (s[i] == 'W') Y ++;
        else Y --;
        int dx = X - x, dy = Y - y;
        ans += mp[ {dx, dy}] * (n - i);
        mp[ {dx, dy}] = 0;
        mp[ {X, Y}] ++;
    }
    cout << ans << '\n';
}

I.Red Playing Cards

思路:其实感觉这个题更像线性的 d p dp dp, f [ i ] f[i] f[i]表示进行删除操作以后的最大价值是多少,因为只有首位一样才可以删,所以对于每一对首位相同的区间我们进行 d p dp dp, d p [ i ] dp[i] dp[i]表示到第 i i i个位置我的最大价值是多少,只有当我的一个区间完全包含在现在遍历的区间之内的时候,我才可能会考虑删还是不删,取 m a x max max即可

void solve() {
    int n; cin >> n;
    vector<int> a(n * 2  + 2);
    unordered_map<int, array<int, 2>> mp;
    for (int i = 1; i <= n * 2; i ++) {
        cin >> a[i];
        if (!mp.count(a[i])) {
            mp[a[i]][0] = i;
        } else {
            mp[a[i]][1] = i;
        }
    }
    vector<array<int, 3>> seg;
    for (auto [x, y] : mp) {
        seg.push_back({x, y[0], y[1]});
    }
    seg.push_back({0, 0, 2 * n + 1});
    sort(seg.begin(), seg.end(), [&](array<int, 3> a, array<int, 3> b) {
        return (a[2] - a[1]) < (b[2] - b[1]);
    });
    vector<int> f(n + 1);
    for (auto [val, l, r] : seg) {
        vector<int> dp(r + 1, 0);
        dp[l] = val;
        for (int i = l + 1; i <= r; i ++) {
            int lo = mp[a[i]][0], hi = mp[a[i]][1];
            dp[i] = max(dp[i], dp[i - 1] + val);
            if (lo > l && hi < r && i >= hi) dp[i] = max(dp[i], dp[lo - 1] + f[a[i]]);
        }
        f[val] = dp[r];
    }
    cout << f[0] << '\n';
}

标签:int,max,++,多校,cin,2024,牛客,mp,dp
From: https://blog.csdn.net/weixin_73914071/article/details/141062096

相关文章

  • 2024,该放弃框架来实现 Web 布局了
    在这里,我并不想评论CSS框架和库的好坏,但一个不争的现实就是,很多Web开发者很容易在众多的CSS框架库中迷失方向。甚至,每个框架和库都向Web开发者承诺,将提供更简单的样式和更流畅的Web布局。然而,在当下,现代CSS特性提供了更简单和更灵活的方法,你完全可以不依赖任何CSS......
  • 【ACM出版,见刊检索快速稳定】第四届物联网与机器学习国际学术会议(IoTML 2024,8月23-25)
    2024年第四届物联网与机器学习国际学术会议(IoTML2024)将于2024年8月23-25日在中国南昌召开。会议将围绕着物联网和机器学习开展,探讨本领域发展所面临的关键性挑战问题和研究方向,以期推动该领域理论、技术在高校和企业的发展和应用,为专注于该研究领域的创新学者、工程师和......
  • 2024年网络信息安全工程师面试题,看看你能做几个?
    一、网络安全网络安全的概念和重要性是什么?常见的网络攻击方式有哪些?网络安全防御措施有什么?计算机病毒和恶意软件有哪些?网络安全法律法规有什么?二、网络协议什么是TCP/IP协议?它包括哪些层次?请简要介绍每个层次的作用。什么是HTTP协议?请简要介绍HTTP协议的......
  • 2024最全最新VMWare以及Linux配置(含yum失效解决方案)
    血泪教训浓缩的精华配置、报错解决(解决99%问题) 目录1.Linux环境搭建1.1安装VMWare1.1.1卸载老版本VMWare(如果有的话) 1.1.2开始安装VMware1.2创建虚拟机1.3安装Centos71.4设置虚拟机快照1.5安装远程连接SSH客户端 重要:新的yum镜像源需要配置(几乎人人都要配置,必......
  • 【保奖思路】2024年华为杯研究生数学建模D题解题思路分享(点个关注,后续会更新
    您的点赞收藏是我继续更新的最大动力!一定要点击如下的卡片链接,那是获取资料的入口!点击链接加入群聊【2024华为杯研赛资料汇】:http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=MwNruKbEvR9aZns1l7xXBWmQQKYAEh-F&authKey=igaBN79pz6BhNlDQ6TIZ5YFAbn71aDcYL77uANPquLF%2FTVgeSAhE......
  • 【保奖思路】2024年华为杯研究生数学建模D题解题思路分享(点个关注,后续会更新
    您的点赞收藏是我继续更新的最大动力!一定要点击如下的卡片链接,那是获取资料的入口!点击链接加入群聊【2024华为杯研赛资料汇】:http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=MwNruKbEvR9aZns1l7xXBWmQQKYAEh-F&authKey=igaBN79pz6BhNlDQ6TIZ5YFAbn71aDcYL77uANPquLF%2FTVgeSAhE......
  • 2024-8-9 算法学习
    P5788【模板】单调栈题意:给定一个数列,求数列中每一个元素之后第一个大于该元素的下标若存在一个数大于它之后的数,那么当我们在左边计算答案的话,那个较小的数不可能被统计到。所以利用单调栈的做法,和右边的比就从右边统计,维护一个栈就行了P6510奶牛排队题意:给定一个数列,求......
  • 项目文档管理利器:2024年你必须了解的工具
    国内外主流的10款项目文档管理软件对比:PingCode、Worktile、Teambition、Tapd、Tower、Confluence、Notion、DropboxPaper、Quip、Basecamp。在面对项目管理的复杂性时,选择合适的文档管理工具可以显著提高效率和团队协作。许多团队在文档管理上遭遇混乱和效率低下,尤其是在处理......
  • 2024.8.9 鲜花
    推歌:早安大森林模拟赛乱写(你猜我欠了多少。嘉然登场确实是好玩的题。考虑先将其分成两组,一组\(<\frack2\),一组\(\ge\frack2\)考虑使一个数在填的时候使所以剩余数都可以填它旁边,或都不可以。可以将每个\(<\frack2\)的数对应其最小可以放的\(\ge\frack2\)的数......
  • Adobe Premiere Pro PR2024中文版win/mac软件安装下载
    一、简介AdobePremierePro2024(简称PR2024)是Adobe公司推出的一款专业视频编辑软件,广泛应用于电影、电视、网络视频制作等领域。作为AdobeCreativeSuite的一部分,PR2024继承了Adobe家族一贯的简洁界面和强大功能,同时结合了最新的技术和用户需求,为用户提供了更加高效、直观......