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

程序员进阶之算法练习(八十二)

作者头像
落影
发布于 2023-08-13 03:13:24
发布于 2023-08-13 03:13:24
20600
代码可运行
举报
文章被收录于专栏:落影的专栏落影的专栏
运行总次数:0
代码可运行

题目1

题目链接 题目大意: 给出一个整数n,构造一个长度为n的整数数组a,满足: 1、1≤𝑎𝑖≤1000 对于所有的 1≤𝑖≤𝑛; 2、𝑎𝑖 能整除𝑖,对于所有的 1≤𝑖≤𝑛; 3、𝑎1+𝑎2+…+𝑎𝑛 能够整除 𝑛 .

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤200) 每个样例一行,整数𝑛 (1≤𝑛≤200)

输出: 对于每个样例,输出符合要求的n个整数;

Examples input 7 1 2 3 4 5 6 7

output 1 2 4 1 2 3 2 8 6 4 3 4 9 4 5 1 10 18 8 5 36 3 6 21 24 10 6 14

题目解析: 对于要求1和要求2比较容易满足,用1、2、3、4、5、、、这样的序列即可; 对于要求3比较特殊,但是可以利用位置1的任何值都能整除1特性,将数组和多余的部分累计在位置1上面。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<deque>
#include<string>
#include<utility>
#include<sstream>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
typedef long long lld;
 
class Solution {
    static const int N = 201010;
    int a[N];
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            int sum = (1 + n) * n / 2;
            int first = 1;
            if (sum % n != 0) {
                first += n - (sum % n);
            }
            cout << first << " ";
            for (int i = 2; i <= n; ++i) cout << i << " ";
            cout << endl;
            
        }
    }
}
ac;
 
int main(int argc, const char * argv[]) {
    // insert code here...
    
    ac.solve();
    
    return 0;
}

题目2

题目链接 题目大意: 有1到n的n个整数数组a,现在这n个整数是unsort的状态,也就是至少存在一个整数a[i] ≠ i; 可以选择一个整数k,对于数组中任意两个整数a[i]和a[j],只要满足i-j=k,则可以交换a[i]和a[j]; 想知道,如果想要把数组调整为有序状态(a[i] = i),整数k最大值可能为多少?

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例2行,第一行整数𝑛 (1≤𝑛≤2⋅1e5) 第二行 n个整数,a1,a2,…,a𝑛 (1≤a𝑖≤𝑛 )

输出: 对于每个样例,输出k的最大可能值;

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

output 1 2 3 4 3 2 3

题目解析: 首先,题目一定有解,比如说k=1的时候,就可以使用冒泡排序,最终使得数组有序; 当k=2的时候,奇数位置的数字可以互相交换,偶数位置的数字可以相互交换;那么要求所有数字与所属位置的距离,应该都为2,或者2的倍数(多次交换,即可得到2的倍数距离); 当k=3的时候,与k=2类似,位置1、2、3只能和4、5、6等位置交换; .. 这样我们将整数数组与所属位置进行匹配,就可以得到整数数组b,排除掉b[i]=0的部分(已经匹配); 只要存在最大公约数k,对于所有的b[i]都有b[i]%k==0,那么这个k是可行的。

那么怎么找到这个k? 有个简单的做法,我们找到最大的整数,将整数进行因数分解,再分别判断每个因素是否为最大公约数即可。 (仔细分析一下,发现这里不要最大整数,取任意整数均可)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<deque>
#include<string>
#include<utility>
#include<sstream>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long lld;

class Solution {
   static const int N = 201010;
   int a[N], 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];
           for (int i = 0; i < n; ++i) b[i] = abs(a[i] - i - 1);
           sort(b, b + n, greater<int>());
           vector<int> tmp;
           tmp.push_back(1);
           tmp.push_back(b[0]);
           for (int i = 2; i * i <= b[0]; ++i) {
               if (b[0] % i == 0) {
                   tmp.push_back(i);
                   tmp.push_back(b[0] / i);
               }
           }
           sort(tmp.begin(), tmp.end(), greater<int>());
           int ans = 0;
           for (int i = 0; i < tmp.size() && !ans; ++i) {
               int ok = 1;
               for (int j = 0; j < n && b[j] != 0; ++j) {
                   if (b[j] % tmp[i] != 0) {
                       ok = 0;
                       break;
                   }
               }
               if (ok) {
                   ans = tmp[i];
               }
           }
           cout << ans << endl;
       }
   }
}
ac;

int main(int argc, const char * argv[]) {
   // insert code here...
   
   ac.solve();
   
   return 0;
}

题目3

题目链接 题目大意: 给出两个整数数组a和b,数组a的元素两两不相同; 现在可以对数组a的元素任意排序,要求: 对于数组a每一个元素a[i],都满足a[i]>b[i]; 问最多有多少种选择?

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例3行,第一行整数𝑛 (1≤𝑛≤2⋅1e5) 第二行 n个整数, 𝑎1 , 𝑎2, …, 𝑎𝑛 (1≤𝑎𝑖≤1e9) 第三行 n个整数,𝑏1 , 𝑏2 , … , 𝑏𝑛 (1≤𝑏𝑖≤1e9 )

输出: 对于每个样例,输出最后的可能数,结果对1e9+7 取余;

Examples input 5 6 9 6 8 4 5 2 4 1 5 6 3 1 3 4 3 2 3 4 9 1 2 1 3 2 3 4 1 3 3 12 2 3 7 10 23 28 29 50 69 135 420 1000 1 1 2 3 5 8 13 21 34 55 89 144

output 32 0 1 0 13824

题目解析: 由题目的要求可以知道,数组的初始顺序并没有意义,那么将a和b从小到大的排序。 接下来,如果出现a[i] <= b[i],题目就无解。因为a[i+1]<=a[i],第i个后面的数字找不到a[x]>b[i];(x > i) 对于每一个整数a[i],如果满足a[i]>b[i],那么我们还可以接着看i+1、i+2、i+3,直到a[x]>b[i]不满足,这些数字都是可选; 那么,我们可以维护一个位置pos,在a[pos]>b[i]的情况下,让pos尽可能靠右; 当我们遇到i+1时,pos同样更新a[pos]>b[i+1];

接下来就是选小球的逻辑:有若干个不同小球,每次选择一个,然后放入若干个,问有多少种不同的选法。 那就是每次选择时候的数量,做一下乘积即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<deque>
#include<string>
#include<utility>
#include<sstream>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long lld;

class Solution {
   static const int N = 201010;
   int a[N], 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];
           for (int i = 0; i < n; ++i) cin >> b[i];
           sort(a, a + n, greater<int>());
           sort(b, b + n, greater<int>());
           lld sum = 1;
           int pos = 1;
           for (int i = 0; i < n; ++i) {
               if (a[i] <= b[i]) {
                   sum = 0;
                   break;
               }
               while (pos < n && a[pos] > b[i]) ++pos;
//                cout << i << " " << pos << " " << sum << endl;
               sum = (sum * (pos - i)) % 1000000007;
           }
           cout << sum << endl;
       }
   }
}
ac;

int main(int argc, const char * argv[]) {
   // insert code here...
   
   ac.solve();
   
   return 0;
}

题目4

题目链接 题目大意: 有n个灯,编号分别为1到n,每个灯有两个参数a[i]和b[i]; 初始状态,n个灯都是关闭的状态,接下来可以进行若干个操作: 选择一个关闭状态的灯i,将其打开,得到分数b[i]; 在这个操作之后,假设亮着的灯有x盏,那么所有a[i] <= x的灯,都会坏掉;(不管是打开,还是关闭的状态)

假设可以任意选择开灯的顺序,问最多能得到多少分。

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例第一行整数𝑛 (1≤𝑛≤2⋅1e5) 接下来n行,每行有整数a𝑖 and b𝑖 (1≤a𝑖,b𝑖≤𝑛 )

输出: 对于每个样例,输出最大的得分数;

Examples input 4 4 2 2 1 6 1 10 1 13 5 3 4 3 1 2 5 3 2 3 3 6 1 2 3 4 1 4 3 4 3 5 2 3 1 1 1

output 15 14 20 1

题目解析: 题目的意思比较难理解,“假设亮着的灯有x盏,那么所有a[i] <= x的灯,都会坏掉“的解释是: 假设点亮1盏灯,那么a[i] <= 1的灯会坏掉; 假设点亮2盏灯,那么a[i] <= 2的灯会坏掉; 也就是说,a[i]越小,灯就越容易坏。

那么可以知道,我们必然会先选择a[i] = 1的灯去打开,并且有且只有一盏a[i]=1的灯能够打开; 同理a[i]=2的灯,最多能打开2盏; a[i]=3的灯,最多能打开3盏; ... 这样就可以知道,a[i]=x的灯,有x盏能打开。

结果就是排序,先按照a[i]从小到大,再按b[i]从大到小即可。 实现逻辑可以用map来降低复杂度。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<deque>
#include<string>
#include<utility>
#include<sstream>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
typedef long long lld;
 
class Solution {
    static const int N = 201010;
    pair<int, int> g[N];
    static bool cmp(pair<int, int> a, pair<int, int> b) {
        if (a.first != b.first) return a.first < b.first;
        else return a.second > b.second;
    }
    
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            for (int i = 0; i < n; ++i) {
                cin >> g[i].first >> g[i].second;
            }
            sort(g, g + n, cmp);
            lld ans = 0;
            map<int, int> vis;
            for (int i = 0; i < n; ++i) {
                if (vis[g[i].first] < g[i].first) {
                    ++vis[g[i].first];
                    ans += g[i].second;
                }
            }
            cout << ans << endl;
        }
    }
}
ac;
 
int main(int argc, const char * argv[]) {
    // insert code here...
    
    ac.solve();
    
    return 0;
}

题目5

题目链接 题目大意: 有整数数组,初始为空数组,接下来执行n次操作: 第i次操作,可以选择整数数组b中的0到i-1,其中一个位置p;在位置p后面增加一个整数0,然后对这个位置p之前的数组b元素执行revert操作(原来0,则会变成1;原来1,则会变成0)

现在知道最终操作完的整数数组结果,我们用数组a表示; 求这n次操作中,每一次操作组成的整数素组;

比如说,已知最终整数数组为[0, 1, 0]; 那么我们第1次可以选择0,得到[0]; 第2次可以选择1,得到[1,0]; 第2次可以选择0,得到[0,1,0]; 这样操作结果组成的整数数组就是[0, 1, 0];

输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例第一行整数𝑛 (1≤𝑛≤2⋅1e5) 第二行,每行有整数a𝑖 (1≤a𝑖≤𝑛 )

输出: 对于每个样例,如果无解,输出NO; 如果有解,先输出YES; 接下来一行,输出n个整数,表示n次操作的结果;(第i个元素表示第i次操作)

Examples input 4 5 1 1 0 0 0 1 1 3 0 1 1 6 1 0 0 1 1 0

output YES 0 0 2 1 3 NO NO YES 0 1 0 2 4 2

题目解析: 根据题目的限制,第i次的选择区间是[0, i-1],那么: 第1次,选择区间是[0, 0]; 第2次,选择区间是[0, 1]; 第3次,选择区间是[0, 2]; 第4次,选择区间是[0, 3]; ... 可以发现,不管如何选择,数组的最后一个元素必然是0,如果为1就无解; 插入整数是0,假设插入的是第0位,那么就是添加元素0; 对于都是0的数组,假设插入的是第x位,那么就是前面x个整数变成1; 接下来就比较简单,对于数组[1, 1, 0],可以用[2, 0, 0]操作结果来表示; 对于整数[0, 1,1, 0],可以拆分为[0] + [1,1,0],那就可以用[0,2,0,0]的操作来表示;

总结来说,就是关注1的部分,将相邻的1合并在一起;假设有x个1在一起,那么就在某个时机选择位置x来生成x个连续的1。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<deque>
#include<string>
#include<utility>
#include<sstream>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
typedef long long lld;
 
class Solution {
    static const int N = 201010;
    int a[N];
    static bool cmp(pair<int, int> a, pair<int, int> b) {
        if (a.first != b.first) return a.first < b.first;
        else return a.second > b.second;
    }
    
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            for (int i = 0; i < n; ++i) {
                cin >> a[i];
            }
            if (a[n - 1]) cout << "NO" << endl;
            else {
                cout << "YES" << endl;
                int pos = 0;
                while (pos < n) {
                    if (!a[pos]) ++pos;
                    int cnt = 0;
                    int tmp = pos;
                    while (a[pos] == 1) {
                        a[pos] = 0;
                        ++pos;
                        ++cnt;
                    }
                    a[tmp] = cnt;
                }
                for (int i = n - 1; i >= 0; --i) cout << a[i] << " ";
                cout << endl;
            }
        }
    }
}
ac;
 
int main(int argc, const char * argv[]) {
    // insert code here...
    
    ac.solve();
    
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
程序员进阶之算法练习(六十)
题目链接 题目大意: 给出一个整数n,求一个最大整数满足: 1、整数各个数字加起来等于n; 2、没有两个相同的数字相邻; 3、数字中不包括0;
落影
2022/04/24
2130
程序员进阶之算法练习(六十)
程序员进阶之算法练习(五十二)
题目链接 题目大意: n个人参加比赛,每个人都有一个分数a[i],现在需要给这些人发奖牌(每个人最多发一个),要求:
落影
2021/05/10
4260
程序员进阶之算法练习(五十二)
程序员进阶之算法练习(七十五)
题目链接 题目大意: 给出整数n、a、b,询问是否存在由数字1到n组成的排列p和q,满足下面条件: 排列p和q的最长公共前缀长度是a; 排列p和q的最长公共后缀长度是b;
落影
2023/03/12
2230
程序员进阶之算法练习(五十一)
正文 题目1 题目链接 题目大意: 给出一个图形,下面是n=1、2、3、4的时候: 现在需要把上面的图形染色,由若干个菱形组成; 问,有多少种染色方法? 输入: 第一行,整数?表示有t个样例数
落影
2021/04/14
3130
程序员进阶之算法练习(五十一)
程序员进阶之算法练习(八十七)
题目链接 题目大意: 给出一个整数的数组,长度为n; 现在可以进行以下的操作: 选择长度不小于2的区间[l, r],将区间内的整数依次进行异或操作,然后将得到的整数替换区间所有的数字;
落影
2023/10/18
1970
程序员进阶之算法练习(八十七)
程序员进阶之算法练习(八十六)
题目链接 题目大意: 给出n个整数,已知这n个整数是按照下面的规则生成。 1、初始化的时候,数组中有2个整数,每次从数组中选择任意两个整数,计算得到他们差值的绝对值,重新放回数组; 2、重复n-2次操作1,得到n个元素的数组。
落影
2023/09/25
1480
程序员进阶之算法练习(八十五)
题目链接 题目大意: 有n个整数的数组a,现在需要给数组每个元素进行染色,注意: 1、每个元素只能有一个颜色; 2、每个元素都要染色; 每个颜色的收益,等于染该色的元素中最大值减去最小值; 问,染色完所有元素后,最大的收益是多少。
落影
2023/09/16
1800
程序员进阶之算法练习(八十一)
题目链接 题目大意: 给出n个整数的数组,现在可以对数组进行以下操作: 选择数组中任意两个不同的整数a[i]和a[j],令a[i]=x,a[j]=y,其中满足x*y = a[i] * a[j];
落影
2023/08/09
3540
程序员进阶之算法练习(八十八)- CF883
题目链接 题目大意: 在地面上有n个点,点都在同一条垂直地面的线上面,每个点的高度为a[i]; 每个点有一条绳子,绳子长度为b[i],一端连着点,一端连着小球(每个点相连的小球是同一个);
落影
2023/10/23
1770
程序员进阶之算法练习(八十八)- CF883
程序员进阶之算法练习(九十八)
题目链接 题目大意: 在一个国际象棋的棋盘上,有一个棋子,它的移动规则类似马,能够朝着横or竖方向移动距离a,然后朝竖or横(和之前不同)移动距离b; 比如说马的移动规则就是a=1,b=2;
落影
2024/02/18
1900
程序员进阶之算法练习(九十八)
程序员进阶之算法练习(七十二)
题目链接 题目大意: 给出一个字符串,由小写字母组成; 现在Alice和Bob在玩游戏,轮流从字符串中移除一个子串,Alice先操作; Alice允许移除偶数长度子串,Bob允许移除奇数长度子串;(也允许不移除) 最终看每个人移除子串的分数总和,字母a是1分,b是2分、、、z是26分; 问最终谁能赢得游戏,以及胜者领先的分数;
落影
2023/03/07
2680
程序员进阶之算法练习(七十九)
题目链接 题目大意: 有n个人参加投票,小明是第一个; 投票一共k轮,每轮每个人会做出一个选择,分别用+和-表示,那么一共有三个结果: +的人数大于-的人数,那么-的人出局; -的人数大于+的人数,那么+的人出局; 如果+和-的人数一样多,那么所有人出局; 出局的人,不再参与后续投票。
落影
2023/07/09
1560
程序员进阶之算法练习(八十)
题目链接 题目大意: 有一个数组a,仅有整数1和-1组成,我们定义数组a的乘积为: 对于 1≤𝑖<𝑗≤𝑛, 𝑎[𝑖]⋅𝑎[𝑗]=1的数量。
落影
2023/07/25
1930
程序员进阶之算法练习(七十四)
题目链接 题目大意: 给出一个整数n,现在可以对整数执行一个操作: 选择整数上两个不同位数的数字交换位置,然后移除整数最右边一位的数字; 重复这个过程,直到整数只剩下1位; 现在想知道这个剩下的数字最小可能为多少。
落影
2023/03/07
2060
程序员进阶之算法练习(一百)
题目链接 题目大意: 给出一个整数,问该整数能否切分为两个数字a和b,满足: 1、a和b都不包括前导零,是一个正常的数字; 2、a和b都大于0; 3、b > a;
落影
2024/03/09
1170
程序员进阶之算法练习(九十九)
题目链接 题目大意: 有三个长度为n的字符串a、b、c,字符串都是小写字符; 有一个长度为n的模版t,模版会与字符串a、b、c匹配,匹配规则如下: 1、假如模版的字符为小写字母,则对应位置必须是相同字符才算匹配; 2、假如模版的字符为大写字母,则对应位置则不能是相同字符才算匹配; 比如说模板abc和字符串abc是匹配的,模板ABC和字符串def也是匹配的,模板ABC和字符串abc是不匹配的;
落影
2024/02/25
1390
程序员进阶之算法练习(九十五)
题目链接 题目大意: 有n个整数的数组a,现在需要构造一个1到n的排列b; 令𝑐𝑖 = 𝑎𝑖−𝑏𝑖,希望最终𝑐𝑖 出现尽可能多的不同整数。
落影
2024/01/06
1290
程序员进阶之算法练习(九十五)
程序员进阶之算法练习(九十三)
题目链接 题目大意: 有3个字符a/b/c,排成一行; 现在可以选择两个字符,交换对应的位置; 上述操作最多只能执行一次,问能否得到abc的顺序。
落影
2023/12/18
1490
程序员进阶之算法练习(六十七)
题目链接 题目大意: 给出n个整数的数组a和b,现在可以执行任意次下面的操作: 选择索引x,交换数组a和b中的元素a[x]和b[x];
落影
2022/10/04
2410
程序员进阶之算法练习(七十七)
题目链接 题目大意: 给出n个整数的数组a,数组的元素可能是1或者2; 现在想要找到一个最小的位置k满足: 𝑎1⋅𝑎2⋅…⋅𝑎𝑘=𝑎𝑘+1⋅𝑎𝑘+2⋅…⋅𝑎𝑛
落影
2023/05/27
2070
相关推荐
程序员进阶之算法练习(六十)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验