Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >程序员进阶之算法练习(九十五)

程序员进阶之算法练习(九十五)

作者头像
落影
发布于 2024-01-06 02:59:07
发布于 2024-01-06 02:59:07
12900
代码可运行
举报
文章被收录于专栏:落影的专栏落影的专栏
运行总次数:0
代码可运行

题目1

题目链接 题目大意: 有n个整数的数组a,现在需要构造一个1到n的排列b; 令𝑐𝑖 = 𝑎𝑖−𝑏𝑖,希望最终𝑐𝑖 出现尽可能多的不同整数。

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤40000) 每个样例两行 第一行整数𝑛(1≤𝑛≤4⋅1e4) 第二行整数𝑎1,𝑎2,…,𝑎𝑛(1≤𝑎𝑖≤1e9)

输出: 每个样例一行,输出符合要求的1-n排列。

Examples input 3 1 100000 2 1 1 3 10 3 3

output 1 2 1 1 3 2

题目解析: 当n=1时,只有1个解; 当n=2时,假如a1<a2,那么令c[1]=a1-2,c[2]=a2-1,由于a1<a2且2>1,那么c1必然<c2; 当n=3时,同理我们可以把3、2、1依次与数组中较小值进行匹配,可以保证最终的值各不相同。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
    static const int N = 201010;
    pair<int, int> a[N];
    int b[N];
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            for (int i = 0; i < n; ++i) {
                cin >> a[i].first;
                a[i].second = i;
            }
            sort(a, a + n);
            for (int i = 0; i < n; ++i) {
                b[a[i].second] = n - i;
            }
            for (int i = 0; i < n; ++i) cout << b[i] << " ";
            cout << endl;
        }
    }
}
ac;

题目2

题目链接 题目大意: 有一个长度为n的01字符串s,现在可以构造另外一个长度为n的字符串L,这个字符串有x个字符为1; 现在想知道当x为0、1、2、3、、、、n时,字符串s和l每个字符按照位置进行异或操作后,最终生产的字符串是否为回文串; 比如说s=101011,当x=2时,我们可以构造字符串L为010100,这样生成的字符串为111111,是回文串;

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤100000) 每个样例两行 第一行整数𝑛,表示字符串长度 (1≤𝑛≤1e5) 第二行字符串s

输出: 每个样例一行,输出长度为n+1的字符串,第i个字符为1表示可以构造有i个字符1的字符串l,使得最终生成字符串是回文串。

Examples input 5 6 101011 5 00000 9 100100011 3 100 1 1

output 0010100 111111 0011111100 0110 11

题目解析: 首先对字符串进行回文串匹配,初始cnt=1,假如某个位置无法匹配回文串的要求,我们用cnt++记录; 这样cnt就可以表示回文串中不匹配的数量,不匹配只有01和10两种情况,此时需要一个字符串1和一个字符0,来进行异或操作;

那么最终x应该要>=cnt,因为需要提供足够多的1来修正不匹配的字符; 但是x也不能太多,因为需要有cnt数量的0来做匹配,最终x要<=n-cnt; 那是否满足cnt <= x <= n-cnt就有解呢? 还要考虑回文串中,是否为奇数。 如果回文串为偶数,那么最终的x - cnt的数量还需要是奇数; 如果回文串为奇数,存在最中间的位置可以任意操作,那么x - cnt可以为奇数或者偶数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
    static const int N = 201010;
    char str[N];
    int ans[N];
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            cin >> str;
            int cnt = 0;
            for (int i = 0; i < n / 2; ++i) {
                if (str[i] != str[n - i - 1]) ++cnt;
            }
            if (!cnt) ans[0] = ans[n] = 1;
            else ans[0] = ans[n] = 0;
            for (int i = 1; i < n; ++i) {
                ans[i] = 0;
                if (i >= cnt && i <= (n - cnt)) {
                    if ((i - cnt) % 2 == 0) { // 剩下为偶数,没有问题
                        ans[i] = 1;
                    }
                    else {
                        if (n % 2) ans[i] = 1; // 中间有留1个位置,可以随意变
                    }
                }
            }
            for (int i = 0; i <= n; ++i) putchar('0' + ans[i]);
            cout << endl;
        }
    }
}
ac;

题目3

题目链接 题目大意: 有一个整数数组s,长度为n;一个数组的MEX值,就是该数组没有出现过的非负整数的最小值,比如说 MEX({0,1,2,4}) = 3 . 现在Alice和Bob两个人在玩游戏,Alice先手。游戏规则如下: Alice可以添加一个整数𝑥(0≤𝑥≤1e9)到数组中,要求该整数在数组中没有; Bob可以移除一个整数y,y必须要小于最近一次Alice添加的整数x,并且该数字在数组存在; Alice的目标是尽可能让数组最终的MEX值更大,Bob的目标是让最终的MEX值尽可能小。

现在让你扮演Alice,使得最终MEX尽可能大。

输入: 第一行,整数𝑡 表示t次游戏 (1≤𝑡≤100000) 每个样例有多行: 第一行整数𝑛(1≤𝑛≤1e5) 第二行整数数组s (0≤𝑠1<𝑠2<…<𝑠𝑛≤1e9) 接下来有多行,每行一个整数y: 如果y>=0,表示Bob从数组中移除该数字; y=-1,表示该次游戏结束;

输出: 每个样例若干行,每行一个整数x,表示要添加的整数;

Examples input 3 5 1 2 3 5 7

7

5

-1

3 0 1 2

0

-1

3 5 7 57

-1 output 8

57

0

3

0

0

样例解释: 样例一的整个操作过程 {1,2,3,5,7 } → {1,2,3,5,7,8 } → {1,2,3,5,8 } → {1,2,3,5,8,57 } → {1,2,3,8,57 } → {0,1,2,3,8,57 }. 最终游戏结束 MEX(𝑆)=4

题目解析: 题目看起来复杂,其实分析下Alice和Bob的策略,会发现逻辑比较简单: Alice想要MEX值尽可能大,那么必须从小开始填充未出现的字符; Bob想要MEX值尽可能小,那么必须从小开始移除出现的字符;

那么为了让题目交互起来更加简单: 先手采用这样的策略,先填充一个数字。 后手移除任何数字,都选择添加该数字。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
    static const int N = 101010;
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            map<int, int> h;
            for (int i = 0;i < n; ++i) {
                int tmp;
                cin >> tmp;
                h[tmp] = 1;
            }
            int first = -1, second = -1;
            for (int i = 0; i < n + 10; ++i) {
                if (h.find(i) != h.end()) continue;;
                if (first == -1) {
                    first = i;
                }
                else if (second == -1) {
                    second = i;
                    break;
                }
            }
            cout << first << endl;;
            while (true) {
                int p;
                cin >> p;
                if (p == -1) break;
                cout << p << endl;
            }
        }
    }
}
ac;

题目4

题目链接 题目大意: 有若干个城市在洪水后被冲毁,现在需要重建; 我们用n x m的矩阵来表示,每个元素都代表一个城市,元素为0表示城市被摧毁,元素为1表示该城市被重建了; 城市重建有两种方式,首先是指定若干个城市直接重建; 另外一种方式,是由其他城市协助重建,可以被协助重建的条件是: 当且仅当这个城市在横、竖两个方向上,都有相邻的城市已经被重建。 比如说 10 11 右上角的城市就可以被协助重建。

现在想知道最少需要指定多少个城市,才能让所有城市都被重建。

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤1000) 每个样例一行,整数 𝑛 and 𝑚 (2≤𝑛,𝑚≤100 )

输出: 每个样例一行,输出满足要求的最小重建数量。

Examples input 3 2 2 5 7 3 2

output 2 7 3

题目解析: 首先从小样例情况开始分析,容易知道n=2,m=2的情况是: 01 10 或者 10 01 剩下的城市协助重建即可。

当增加到3x3时候,考虑可以直接从2x2的基础上开始思考,并且为了充分利用协助重建,我们可以假设2x2已经完全重建。 110 110 000 这样我们很容易想到,只需要在右下角添加 一个1,剩下的1可以自动补齐。

至此,我们很容易得到一个策略,就是不断在右下角添加数字,得到一个最优解。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
    static const int N = 201010;
    int dir[4][2] = {1,1,  -1,1,  1,-1,   -1,-1};
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n, m;
            cin >> n >> m;
            /*
             01000
             10000
             00100
             00011
             */
            cout << 2 + max(n - 2, m - 2) << endl;
        }
    }
}
ac;

题目5

题目链接 题目大意: 给出一个n个节点的树,现在每次可以选择两个节点,将两个节点之间的最短路径上,所有节点都合并成一个节点,类似下图的操作:

和原来节点相连的边,改为和新合并成的点相连。

问,最少要进行多少次操作,剩下的节点只有1个。

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤1000) 每个样例第一行,整数 𝑛 (2≤𝑛≤100000) 接下来n-1行,整数 𝑢𝑖 and 𝑣𝑖 ,表示两个点之间存在一条边 (1≤𝑢𝑖,𝑣𝑖≤𝑛,𝑢𝑖≠𝑣𝑖 )

输出: 每个样例一行,输出满足要求的最小操作次数。

Examples input 4 4 1 2 1 3 3 4 9 3 1 3 5 3 2 5 6 6 7 7 8 7 9 6 4 7 1 2 1 3 2 4 4 5 3 6 2 7 6 1 2 1 3 1 4 4 5 2 6

output 1 3 2 2

题目解析: 题目给出来的图,就比较好分析。 每次操作都会减少若干个节点,最终是从n个节点变成1个节点,这是一个节点数量单调递减的过程。 那么可以知道,每次应该尽可能多的去选择节点,比如说从根节点到叶子节点作为一条路径,我们每次选择两条最长的路径,组成一条当前树上的最长路径,进行合并。 但是这种做法,如何证明就是最优解?有没有可能局部最优会破坏全局最优。 在思索和这个过程的时候发现,沿着上面的思路,每次选择两条到叶子节点的路径,融合之后就会减少一个叶子节点。当不存在叶子节点的时候,就只剩下一个节点。 这个过程的最优性也比较容易保证,对于有m个叶子节点的树,每次操作只能减少2个叶子节点。最优解就是m/2。

剩下的问题,就是如何确定根节点? 答案就是不需要根节点,从任意点出发,只有一个点相连就是叶子节点,计算叶子节点数量即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
    static const int N = 201010;
    vector<int> g[N];
    int dfs(int u, int fat) {
        int ret = g[u].size() == 1;
        for (int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            if (v == fat) continue;;
            ret += dfs(v, u);
        }
        return ret;
    }
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            for (int i = 0; i <= n; ++i) g[i].clear();
            for (int i = 1; i < n; ++i) {
                int u, v;
                cin >> u >> v;
                g[u].push_back(v);
                g[v].push_back(u);
            }
            cout << (dfs(1, 0) + 1) / 2 << endl;
        }
    }
}
ac;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
程序员进阶之算法练习(八十一)
题目链接 题目大意: 给出n个整数的数组,现在可以对数组进行以下操作: 选择数组中任意两个不同的整数a[i]和a[j],令a[i]=x,a[j]=y,其中满足x*y = a[i] * a[j];
落影
2023/08/09
3530
程序员进阶之算法练习(六十三)
按照上面的规则,迭代k次之后,得到a[k]; 现在给出a[1]和k,求最终迭代出来的a[k]值是多少?
落影
2022/09/02
2480
程序员进阶之算法练习(六十三)
程序员进阶之算法练习(九十七)
现在光标停留在最左边的数字1处,我们可以进行以下的操作: 1、将当前光标所在位置的数字输出; 2、移动光标到相邻的数字,比如说从1移动到2,从2移动到3;(1的左边不能移动,0的右边不能移动)
落影
2024/02/10
1130
程序员进阶之算法练习(九十七)
程序员进阶之算法练习(七十二)
题目链接 题目大意: 给出一个字符串,由小写字母组成; 现在Alice和Bob在玩游戏,轮流从字符串中移除一个子串,Alice先操作; Alice允许移除偶数长度子串,Bob允许移除奇数长度子串;(也允许不移除) 最终看每个人移除子串的分数总和,字母a是1分,b是2分、、、z是26分; 问最终谁能赢得游戏,以及胜者领先的分数;
落影
2023/03/07
2680
程序员进阶之算法练习(九十九)
题目链接 题目大意: 有三个长度为n的字符串a、b、c,字符串都是小写字符; 有一个长度为n的模版t,模版会与字符串a、b、c匹配,匹配规则如下: 1、假如模版的字符为小写字母,则对应位置必须是相同字符才算匹配; 2、假如模版的字符为大写字母,则对应位置则不能是相同字符才算匹配; 比如说模板abc和字符串abc是匹配的,模板ABC和字符串def也是匹配的,模板ABC和字符串abc是不匹配的;
落影
2024/02/25
1380
程序员进阶之算法练习(八十三)
题目链接 题目大意: 有长度为n的整数数组a,数组元素都由-1和1组成; 现在每次可以选择一个数组位置,翻转位置上元素(-1变成1,1变成-1); 假如想要实现下面的要求,最少需要多少次操作: 𝑎1+𝑎2+…+𝑎𝑛≥0 𝑎1⋅𝑎2⋅…⋅𝑎𝑛=1
落影
2023/08/20
2430
程序员进阶之算法练习(九十三)
题目链接 题目大意: 有3个字符a/b/c,排成一行; 现在可以选择两个字符,交换对应的位置; 上述操作最多只能执行一次,问能否得到abc的顺序。
落影
2023/12/18
1490
程序员进阶之算法练习(八十五)
题目链接 题目大意: 有n个整数的数组a,现在需要给数组每个元素进行染色,注意: 1、每个元素只能有一个颜色; 2、每个元素都要染色; 每个颜色的收益,等于染该色的元素中最大值减去最小值; 问,染色完所有元素后,最大的收益是多少。
落影
2023/09/16
1790
程序员进阶之算法练习(九十四)
题目链接 题目大意: 有n个整数组成的数组a,现在可以对数组a的元素任意打乱顺序,要求满足: 假设打乱后的数组是b,要满足:𝑏1+𝑏2=𝑏2+𝑏3=…=𝑏𝑛−1+𝑏𝑛=k 也就是相邻两个数字的和相同。
落影
2023/12/23
1050
程序员进阶之算法练习(九十四)
程序员进阶之算法练习(八十七)
题目链接 题目大意: 给出一个整数的数组,长度为n; 现在可以进行以下的操作: 选择长度不小于2的区间[l, r],将区间内的整数依次进行异或操作,然后将得到的整数替换区间所有的数字;
落影
2023/10/18
1970
程序员进阶之算法练习(八十七)
程序员进阶之算法练习(七十五)
题目链接 题目大意: 给出整数n、a、b,询问是否存在由数字1到n组成的排列p和q,满足下面条件: 排列p和q的最长公共前缀长度是a; 排列p和q的最长公共后缀长度是b;
落影
2023/03/12
2230
程序员进阶之算法练习(八十)
题目链接 题目大意: 有一个数组a,仅有整数1和-1组成,我们定义数组a的乘积为: 对于 1≤𝑖<𝑗≤𝑛, 𝑎[𝑖]⋅𝑎[𝑗]=1的数量。
落影
2023/07/25
1930
程序员进阶之算法练习(九十八)
题目链接 题目大意: 在一个国际象棋的棋盘上,有一个棋子,它的移动规则类似马,能够朝着横or竖方向移动距离a,然后朝竖or横(和之前不同)移动距离b; 比如说马的移动规则就是a=1,b=2;
落影
2024/02/18
1880
程序员进阶之算法练习(九十八)
程序员进阶之算法练习(七十八)
题目链接 题目大意: 在二维坐标系中,每次有两个走法: 1、从(𝑥,𝑦) 到 (𝑥+1, 𝑦+1); 2、从(𝑥,𝑦) 到 (𝑥-1, 𝑦);
落影
2023/07/09
1610
程序员进阶之算法练习(七十九)
题目链接 题目大意: 有n个人参加投票,小明是第一个; 投票一共k轮,每轮每个人会做出一个选择,分别用+和-表示,那么一共有三个结果: +的人数大于-的人数,那么-的人出局; -的人数大于+的人数,那么+的人出局; 如果+和-的人数一样多,那么所有人出局; 出局的人,不再参与后续投票。
落影
2023/07/09
1560
程序员进阶之算法练习(六十二)AK练习
题目链接 题目大意: 小明有a个1元硬币,b个2元硬币; 小明想要购买一个商品,并且不想找零; 现在小明想知道自己无法给到最低价格是多少;
落影
2022/06/05
5450
程序员进阶之算法练习(一百)
题目链接 题目大意: 给出一个整数,问该整数能否切分为两个数字a和b,满足: 1、a和b都不包括前导零,是一个正常的数字; 2、a和b都大于0; 3、b > a;
落影
2024/03/09
1170
程序员进阶之算法练习(八十八)- CF883
题目链接 题目大意: 在地面上有n个点,点都在同一条垂直地面的线上面,每个点的高度为a[i]; 每个点有一条绳子,绳子长度为b[i],一端连着点,一端连着小球(每个点相连的小球是同一个);
落影
2023/10/23
1770
程序员进阶之算法练习(八十八)- CF883
程序员进阶之算法练习(七十一)
题目链接 题目大意: 给出n个整数,每次可以选择其中两个整数a[i]和a[j],令a[i]=x和a[j]=y,但是需要满足a[i] | a[j] = x | y;(|是或操作) 现在可以进行任意次操作,问n个整数的最小和是多少。
落影
2023/01/01
2230
程序员进阶之算法练习(六十四)
题目链接 题目大意: 给出一个字符串(由26个大写字母组成),询问这个字符串中,是否相同的字母都连在一起。
落影
2022/09/08
2390
相关推荐
程序员进阶之算法练习(八十一)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验