寒假训练赛第二场 -- 思维题

2023-05-16

题解

    • A - 01 Game
        • 题意:
        • 思路:
        • AC代码
    • B - String Task
        • 题意
        • 思路
        • AC代码
    • C - Sereja and Suffixes
        • 题意
        • 思路
        • AC代码
    • D - XXXXX
        • 题意
        • 思路
        • AC代码
    • E - Swap Adjacent Elements
        • 题意
        • 思路
        • AC代码
    • F - Nice Matrix
        • 题意
        • 思路
        • AC代码
    • G - Mortal Kombat Tower
        • 题意
        • 思路
        • AC代码
    • H - Balanced Team
        • 题意
        • 思路
        • AC代码
    • I - Cutting
        • 题意
        • 思路
        • AC代码
    • J - Brutality
        • 题意
        • 思路
        • AC代码

A - 01 Game

题意:

Alice 和 Bob 在玩游戏。
初始有一个仅由01构成的字符串。Alice 和 Bob 轮流进行游戏,Alice 先行。轮到某个人的时候,他需要从原串中找到并删除两个相邻且不同的字符(01或10),无法操作者输。
两人都用最优的策略进行,你需要确定谁能够赢得游戏。

思路:

如果字符串是010101…或者是101010…这种格式,则求出01或10的对数就能求出获胜方;
那如果字符串不是上面这样的格式呢,其实同理我们也是记录01或者10对数,因为如果1和0都存在,必然会至少1个10是挨着的,删除了过后,又会挨在一起。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 200;
char s[MAXN];
void solve() {
    scanf("%s", s);
    int len = strlen(s);
    int cnt1 = 0, cnt0 = 0;
    for (int i = 0; i < len; ++i) {
        if (s[i] == '0') {
            cnt0++;
        } else {
            cnt1++;
        }
    }
    int t = min(cnt0, cnt1);
    if (t & 1) {
        puts("DA");
    } else {
        puts("NET");
    }
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}

B - String Task

题意

将一个字符串中的元音字母删除(Y也是哦),同时在每个辅音字母前面加入’.'以及变成小写。

思路

直接模拟即可。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 200;
char s[MAXN];
set<char> st;
void init() {
    st.insert('A'); st.insert('a');
    st.insert('O'); st.insert('o');
    st.insert('Y'); st.insert('y');
    st.insert('E'); st.insert('e');
    st.insert('U'); st.insert('u');
    st.insert('I'); st.insert('i');
}
void solve() {
    scanf("%s", s);
    int len = strlen(s);
    init();
    string ans = "";
    for (int i = 0; i < len; ++i) {
        if (st.find(s[i]) == st.end()) {
            ans += '.';
            ans += s[i] < 97 ? s[i] + 32: s[i];
        }
    }
    cout << ans;
}
int main() {
    int t = 1;
    //scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}

C - Sereja and Suffixes

题意

nuoyanli有一个数组 a,包含了 n 个整数 a1, a2, …, an。 他吃饱了撑着想研究一下这个数组。 于是他拿出一张纸,写下了 m 个整数 l1, l2, …, lm (1 ≤ li ≤ n)。他想知道,在数组 a 中,对于每个指定的位置li , 有多少个不同的数字处于位置li, li + 1, …, n。(即从第 li 个元素开始到结尾,有多少个不同的元素)?
nuoyanli写出了必要的数组元素,但是数组太大了,时间紧迫,请最最最可爱的yy帮帮他,为每个 li找到所描述问题的答案。

思路

后缀数组+标记法
从后往前遍历,如果没有出现过的数字,就等于后一个位置一共有多少个不同的数+1,如果出现过,则就等于后一个位置一共有多少个不同的数。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 5;
int a[MAXN], sum[MAXN], vis[MAXN];
void solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    memset(vis, 0, sizeof(vis));
    memset(sum, 0, sizeof(sum));
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    for (int i = n; i >= 1; --i) {
        if (vis[a[i]]) {
            sum[i] = sum[i + 1];
        } else {
            sum[i] = sum[i + 1] + 1;
            vis[a[i]] = 1;
        }
    }
    while(m--) {
        int x;
        scanf("%d", &x);
        printf("%d\n", sum[x]);
    }
}
int main() {
    solve();
    return 0;
}

D - XXXXX

题意

埃哈布(Ehab)喜欢数字理论,但出于某种原因,他讨厌数字x。 给定一个数组a,找到其最长子数组的长度,以使其元素之和不能被xx整除,或者确定该子数组不存在.

思路

我们可以利用双指针往中间扫的思想来做,目的一直在维护一个不被x整除的子数组。当满足数组和为下的倍数时收缩,有以下四种情况
1.如果最左边的元素不是x的倍数,最右边的元素是x的倍数,则收左边。
2.如果最右边的元素不是x的倍数,最左边的元素是x的倍数,则收右边。
3.如果两边都是x的倍数,没办法都要往中间靠。
4.如果两边都不是x的倍数,随便收缩一边即可。
当然这个思路会有一个弊端,可能把连续0删除了,例如
n = 5,x = 2.
0 1 1 1 1 0
这样我们最终得到的是111,但是还有最优的是0111.
所以最后还需要往两边扫连续0的情况。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 5;
int a[MAXN];
void solve() {
    int n, x, sum = 0;
    scanf("%d%d", &n, &x);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        sum += a[i];
    }
    int ans = n, l = 1, r = n;
    while(l <= r) {
        if (sum % x == 0) {
            if (a[r] % x == 0 && a[l] % x) {
                sum -= a[l];
                l++;
                ans--;
            } else if (a[l] % x == 0 && a[r] % x){
                sum -= a[r];
                r--;
                ans--;
            } else if (a[l] % x ==0 && a[r] % x == 0){
                sum -= a[l] + a[r];
                l++;
                r--;
                ans -= 2;
            } else {
                sum -= a[l];
                l++;
                ans--;
            }
        } else {
            break;
        }
    }
    // 处理有0的情况。
    if (sum % x != 0) {
        while(a[l - 1] % x == 0 && l > 1) {
            l--;
            ans++;
        }
        while(a[r + 1] % x == 0 && r < n) {
            r++;
            ans++;
        }
    }
    printf("%d\n", ans == 0 ? -1 : ans);
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}

E - Swap Adjacent Elements

题意

您有一个由n个整数组成的数组。 从1到n的每个整数在此数组中仅出现一次。
对于某些索引 i(1≤i≤n-1),可以用第i + 1交换第i个元素,而对于其他索引,则不可能。 您可以按任何顺序执行任意数量的交换操作。 对于将第i个元素与第(i + 1)个交换的次数没有限制(如果位置不被禁止)。
您可以执行一些交换操作序列来使此数组升序排序吗?

思路

如果利用冒泡排序思想标记哪些位置可以交换,最后判断交换(n + 1)*n/2次过后是否升序,那么这个题就T了,冒泡不行,我们就可以使用sort对连续的1进行一个排序,这样会大大降低复杂度,算法复杂度为O(nlogn)。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 200000 + 20;
int a[MAXN], vis[MAXN];
void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    getchar();
    char c;
    for (int i = 1; i <= n; ++i) {
        scanf("%c", &c);
        c == '1' ? vis[i] = 1 : vis[i] = 0;
    }
    for (int i = 1; i <= n; ++i) {
        if (vis[i] == 1) {
            int j = i;
            for ( ;vis[j] && j <= n; ++j) {

            }
            sort(a + i, a + j + 1);
            i = j;
        }
    }
    for (int i = 2; i <= n; ++i) {
        if (a[i] < a[i - 1]) {
            puts("NO");
            return;
        }
    }
    puts("YES");
}
int main() {
    solve();
    return 0;
}

F - Nice Matrix

题意

做出如下定义,
一个n*m的矩阵,如果它的所有行以及所有列都是回文串,则称这个矩阵为nice
每次操作:你可以对矩阵中的一个元素进行+1或者-1
请回答使得该矩阵变为nice矩阵所需要的最少操作数

思路

设当前元素为a[i][j], 由于题目说形成所有行和列都是回文,则会联系到a[n - i + 1][j], a[i][m - j + 1]以及a[n - i + 1][m - j + 1],这四个位置上的数必然要相等的,不妨设四个位置上的数为a,b,c,d;将问题的子问题转化为,设一个x,abcd与x距离和最小。
令y = |x - a| + |x - b| + |x - c| + |x - d|, a < b < c < d, 求y在哪些范围内取得最小值?
使用分类讨论法:
当x < a时,y = a + b + c + d - 4x;当x = a时最小,y = b + c + d - 3a;
当a <= x < b时, y = -a + b + c + d - 2x; 当 x = b时最小, y = c + d - a - b;
当b <= x < c时,y = -a - b + c + d; y = c + d - a - b;
当c <= x < d时,y = - a - b - c + d + 2x; 当 x = c时最小, y = c + d - a - b;
当x >= d时, y = - a - b - c - d + 4x;当x = d时最小,y = 3d - a - b - c;
综上可得,当 b <= x <= c 时y取得最小值。
即我们将四个相连位置上的数变成第二小或者第三小的数即可。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 200;
ll a[MAXN][MAXN], b[MAXN][MAXN];
ll ans;
void solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            scanf("%lld", &a[i][j]);
            b[i][j] = a[i][j];
        }
    }
    ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            ll c[4];
            c[0] = a[i][j];
            c[1] = a[n - i + 1][j];
            c[2] = a[i][m - j + 1];
            c[3] = a[n - i + 1][m - j + 1];
            sort(c, c + 4);
            a[i][j] = a[n - i + 1][j] = a[i][m - j + 1] = a[n - i + 1][m - j + 1] = c[1];// c[1] <= x <= c[2]都可
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            ans += abs(a[i][j] - b[i][j]);
        }
    }
    printf("%lld\n", ans);
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}

G - Mortal Kombat Tower

题意

你和你的朋友去通过一个挑战塔,这个挑战塔有n层,每层有挑战等级(ai = 0表示容易,ai=1表示困难),你的朋友只能通过容易的层数,困难等级的只能跳过,而你都可以通过。你和你的朋友只能挑战1层或者两层,只能连续挑战不能跳越层数挑战,你和你的朋友来回调整。最开始的回合数是你朋友,挑战n层,问你的朋友跳过的次数。

思路

你朋友每次都是选择最优的,而你的选择也会影响到后面你朋友的选择,经典dp问题。
设dp[i][0]表示朋友回合时当前跳过数,dp[i][1]表示自己的回合朋友的跳过数。
转移方程为
dp[i][0] = min(dp[i - 1][1] + a[i], dp[i - 2][1] + a[i] + a[i - 1]);
dp[i][1] = min(dp[i - 1][0], dp[i - 2][0]);

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e5 + 5;
int a[MAXN], dp[MAXN][2];
void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    dp[1][0] = a[1];
    dp[2][0] = a[1] + a[2];

    dp[1][1] = INF;//肯定不是我解决的。
    dp[2][1] = dp[1][0];
    for (int i = 3; i <= n; ++i) {
        dp[i][0] = min(dp[i - 1][1] + a[i], dp[i - 2][1] + a[i] + a[i - 1]);
        dp[i][1] = min(dp[i - 1][0], dp[i - 2][0]);
    }
    printf("%d\n", min(dp[n][1], dp[n][0]));
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}

H - Balanced Team

题意

下面给出一些元素,假定集合A为集合内元素差不超过5,输出这个集合可能的最大值。

思路

排序+二分:二分枚举a[i] + 5的位置再减去i的位置,即为集合元素。取最大即可。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 5;
int a[maxn];
void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
    }
    sort(a, a + n);
    int ans = 0;
    for (int i = 0; i < n; ++i) {
        ans = max(ans, upper_bound(a + i, a + n, a[i] + 5) - a - i);
    }
    printf("%d\n", ans);
}
int main() {
    solve();
    return 0;
}

I - Cutting

题意

给你一个正整数n.
以及一个整数序列a[1…n].
现在,你需要决定是否要在a[i]和ai+1切割一次,使得这个序列分成若干个序列。
且要求,全部切割完以后,每个序列中,奇数和偶数出现的次数都是一样的.
如{1,2,3,4}可以切割一次变成{1,2}{3,4}两个序列,且每个序列中奇数和偶数出现的次数都是一样的为1.
每切割一次的代价是|a[i]-a[i+1]|.
问你在不超过B代价的情况下,你最多能对这个序列切割几次?

思路

寻找哪些可以切割,可以切割的价值存进set里面(小->大),然后用B减去相应的代价,得到的最大切割次数即可。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 200;
int a[MAXN], odd[MAXN], even[MAXN];
void solve() {
    int n, B;
    scanf("%d%d", &n, &B);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        if (a[i] & 1) {
            odd[i] = odd[i - 1] + 1;
            even[i] = even[i - 1];
        } else {
            odd[i] = odd[i - 1];
            even[i] = even[i - 1] + 1;
        }
    }
    if (odd[n] != even[n]) {
        puts("0");
    }
    multiset<int> st;
    for (int i = 2; i < n; i += 2) {
        if (odd[i] == even[i]) {
            st.insert(abs(a[i] - a[i + 1]));
        }
    }
    int ans = 0;
    for (set<int>::iterator it = st.begin(); it != st.end(); ++it) {
        if (B >= (*it)) {
            B -= *it;
            ans++;
        } else {
            break;
        }
    }
    printf("%d\n", ans);
}
int main() {
    solve();
    return 0;
}

J - Brutality

题意

有一个26个按键(每个写着一个字符的)的键盘 某个字母不能连续按超过k次,输出最多的按键次数

思路

将连续相同字母从大到小排序,取前最大的k个即可。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e5 + 5;
int a[MAXN];
char s[MAXN];
bool cmp(const int& x, const int& y) {
    return x > y;
}
void solve() {
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
    }
    scanf("%s", s);
    ll ans = 0;
    for (int i = 0; i < n;) {
        int j = i;
        for (;s[j] == s[i]; j++) {
        }
        //printf("j == %d\n", j);
        sort(a + i, a + j, cmp);
        for (int l = i; l < j; ++l) {
            if (l - i >= k) break;
            ans += a[l];
        }
        i = j;
    }
    printf("%lld\n", ans);
}
int main() {
    solve();
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

寒假训练赛第二场 -- 思维题 的相关文章

  • JavaEE_FinalProject

    基于Springboot xff0c jsp和mybatis的作业管理系统 系统需求 可登陆 xff0c 分为学生和老师两端 xff0c 根据账号进行不同分类 老师可以查看作业 xff0c 添加学生并且添加作业 学生可以查看作业 xff0c
  • Debian10搭建dhcp服务

    文章目录 1 安装dhcp服务2 设置网卡监听3 配置dhcp参数4 重启dhcp服务5 测试6 易错总结 1 安装dhcp服务 apt install y isc dhcp server 等待安装完成即可 xff08 这里有一个报错 xf
  • Debian10搭建ntp服务

    文章目录 1 所需设备2 任务描述3 安装ntp服务4 配置ntp服务器4 安装ntpdate客服端5 Debian10Client设置计划任务6 易错总结 1 所需设备 两台Debian10Debian10Server 网卡信息 xff1
  • win11安装的Ubuntu20.04子系统出现System has not been booted with systemd as init system (PID 1)问题的解决流程

    目录 一 前言 二 具体解决方法 第一步 xff1a 切换root用户至自己账号 第二步 xff1a 重新安装xrdp 第三步 xff1a 重新配置端口并启动xrdp 第四步 xff1a 打开远程连接窗口 第五步 xff1a 点击连接 xf
  • 方面级情感分析综述论文&论文+讲解+复现(ABSA)

    2022最新方面级别情感分析论文综述 A Survey on Aspect Based Sentiment Analysis Tasks Methods and Challenges 其中关于ASTE Data V2数据集的论文 1 论文地
  • 使用Go语言开发Qt界面

    Go 的 UI 库 Go 语言本身是没有 UI 库的 xff0c 不过有许多第三方的库支持将 Go 语言绑定到其他 UI 库 xff0c 比如 Qt GTK 参考地址 环境搭建 非 windows 或者需要参数说明的可以参考官方的wiki
  • GitHub AI 编程工具自动写代码神器Copilot插件体验

    简介 copilot 是一个基于 AI 的编程辅助工具 目前已经集成在了 vscode 中 xff0c 后续可能集成到更多平台和工具 xff0c 目前还是测试阶段 官网地址 https copilot github com 支持所有语言 c
  • WebStorm NodeJS

    按 Create New Project 選擇 Empty Project 選擇自己的Directory 作為Location Location 最尾是代表Project Name 改為Hello World 創建一個Javascript
  • wsl ubuntu22.04 conda环境安装labelImg解决xcb缺失问题

    labelImg 安装 pip install PyQt5 i https pypi tuna tsinghua edu cn simple pip install pyqt5 tools i https pypi tuna tsinghu
  • 7个大一C语言必学的程序 / C语言经典代码大全

    嗨 大家好 xff0c 这里是可莉 xff01 今天给大家带来的是7个C语言的经典基础代码 那一起往下看下去把 程序一 打印100到200之间的素数 include lt stdio h gt int main int i for i 61
  • 字符串转化为枚举类型

    需求 xff1a 通过配置文件中自定义传入枚举类型的值 span class token annotation punctuation 64 value span span class token punctuation span span
  • NAT和PAT的原理及配置

    文章目录 一 NAT1 NAT概述2 私有地址3 NAT工作原理4 NAT功能5 NAT包含4类地址6 NAT的实现方式 二 静态转换 xff08 Static Translation xff09 三 动态转换 xff08 Dynamic
  • Linux系统安装教程(手把手教学)

    文章目录 1 首先 xff0c 打开虚拟机 xff0c 点击新建虚拟机2 点击下一步 xff0c 再点击稍后安装3 操作系统选择Linux xff0c 版本选择CentOS7 64位4 命名虚拟机5 设置磁盘大小为100GB6 设置内存为4
  • NFS共享存储服务

    文章目录 引言一 NFS概述二 安装 nfs utils rpcbind 软件包三 NFS的特点四 实验步骤1 安装nfs和rpcbind软件2 设置共享目录3 启动 NFS服务并验证结果4 客户机中访问 NFS 共享资源4 1 手动挂载
  • 优化命令之Sar命令

    文章目录 引言一 sar简介1 sar命令常用格式2 常用选项3 常用参数 二 Sar常用性能数据三 CPU资源监控1 整体CPU使用统计 xff08 u xff09 2 各个CPU使用统计 P 3 将CPU使用情况保存到文件中 四 内存监
  • MySQL高级SQL语句

    文章目录 引言一 常用查询1 order by按关键字排序1 1 升序排序1 2 降序排序1 3 结合where进行条件过滤再排序1 4 多字段排序 2 and or判断2 1 and or 且与或的使用2 2 嵌套 多条件使用 3 dis
  • MongoDB搭建及基础操作

    文章目录 引言一 MongoDB概述1 什么是MongoDB2 MongoDB的特点3 MongoDB适用场景4 MongoDB概念解析 二 搭建MongoDB1 关闭系统防火墙和安全机制2 配置mongodb源仓库3 安装mongodb4
  • 【云原生之k8s】k8s之持久化存储PV、PVC

    文章目录 一 PV和PVC1 PV 概念2 PVC概念3 PV 与 PVC 之间的关系3 1 PV和PVC的生命周期3 2 一个PV从创建到销毁的具体流程3 3 三种回收策略3 4 查看pv pvc的定义方式 规格 4 两种PV的提供方式
  • react native 这样理解运行机制

    移动开发中 xff0c native开发性能和效果上无疑是最好的 但是在众多的情况下 xff0c native开发并不是最优的选择 当需求经常改动的时候 xff0c 当预算有限的时候 xff0c 当deadline很近的时候 xff0c n
  • Promethues原理详解

    目录 引言 一 Prometheus 概述 1 什么是Prometheus 2 Zabbix和Prometheus区别 3 Prometheus的特点 二 运维监控平台设计思路 三 Prometheus监控体系 1 系统层监控 xff08

随机推荐