2021-12-16【Codeforces Round #761 (Div. 2)】【题解A-C】

本文解析了三项算法挑战赛题目:构造不含特定子序列的最小字典序字符串、寻找符合特定条件的三个整数以及通过有限操作将数组转换为排列。提供了详细的解题思路和代码实现。

A. Forbidden Subsequence

题目详情

给定字符串 SSSTTT,由小写英文字母组成。保证 TTT 是字符串 abcabcabc 的排列。

找到字符串 S′S'S,即 SSS 的字典序最小排列,使得 TTT 不是 S′S'S 的子序列。

如果两个字符串中每个不同字符的出现次数相同,则字符串 aaa 是字符串 bbb 的排列。

如果可以通过删除多个(可能为零或所有)元素从 bbb 中获得 aaa,则字符串 aaa 是字符串 bbb 的子序列。

当且仅当以下条件之一成立时,字符串 aaa 在字典序上小于字符串 bbb

a是b的前缀,但a≠ba≠ba=b
aaabbb 不同的第一个位置,字符串 aaa 有一个字母在字母表中比 bbb 中的相应字母出现得更早。

输入

每个测试包含多个测试用例。第一行包含一个整数 t(1≤t≤1000)t (1≤t≤1000)t(1t1000)——测试用例的数量。测试用例的描述如下。

每个测试用例的第一行包含一个字符串 S(1≤∣S∣≤100)S (1≤|S|≤100)S(1S100),由小写英文字母组成。

每个测试用例的第二行包含一个字符串 TTT,它是字符串 abc 的排列。 (因此,∣T∣=3|T|=3T=3)。

注意∣S∣|S|S的总和没有限制跨所有测试用例。

输出

对于每个测试用例,输出单个字符串 S′S'S,即 SSS 的字典序最小排列,使得 TTT 不是 S′S'S 的子序列。

code:

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;

const int maxn=1e6+5;
void solve(){
    string s, t, s1;
    cin >> s;
    cin >> t;
    sort(s.begin(), s.end());
    int a[5]={0};
    for (int i = 0; i < s.length();i++){
        if(s[i]=='a')
            a[0]++;
        if(s[i]=='b')
            a[1]++;
        if(s[i]=='c')
            a[2]++;
    }
    if(a[0]&&a[1]&&a[2]&&t=="abc"){
        for (int i = 0; i < a[0];i++)
            cout << "a";
        for (int i = 0; i < a[2];i++)
            cout << "c";
        for (int i = 0; i < a[1];i++)
            cout << 'b';
       // cout << "!";
        cout << s.substr(a[0] + a[1] + a[2]) << endl;
    }else{
        cout << s << endl;
    }
}

int main(){
    ios::sync_with_stdio(0);
    int t;
    cin >> t ;
    while(t--){
         solve();
    }
    return 0;
}

B. GCD Problem

题目详情

给定一个正整数 n。 找出三个不同的正整数 a、b、ca、b、cabc,使得 a+b+c=na+b+c=na+b+c=ngcd(a,b)=cgcd(a,b)=cgcd(a,b)=c,其中 gcd(x,y)gcd(x,y)gcd(x,y) 表示整数 x 和 y 的最大公约数 (GCD)。

输入

输入由多个测试用例组成。 第一行包含一个整数 t(1≤t≤105)t (1≤t≤10^5)t(1t105)——测试用例的数量。 测试用例的描述如下。

每个测试用例的第一行也是唯一一行包含一个整数 n(10≤n≤109)n (10≤n≤10^9)n(10n109)

输出

对于每个测试用例,输出满足要求的三个不同的正整数a、b、ca、b、cabc。 如果有多个解决方案,您可以打印任何一个。 我们可以证明答案总是存在的。

coed:

在这里插入图片描述


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;

const int maxn = 1e6 + 5;
ll gcd(ll a, ll b){
    return a % b == 0 ? b : gcd(b, a % b);
}
void solve(){
    ll n, i;
    cin >> n;
    if (n % 2 == 0){
        cout << (n - 1) / 2 << " " << (n - 1) / 2 + 1 << " " << 1 << endl;
    }
    else{
        if ((n - 1) / 2 % 2 == 0){
            cout << (n - 1) / 2 - 1 << " " << (n - 1) / 2 + 1 << " " << 1 << endl;
        }
        else{
            cout << (n - 1) / 2 - 2 << " " << (n - 1) / 2 + 2 << " " << 1 << endl;
        }
    }
    //cout << 1 << " " << n - 2 << " " << 1 << endl;
}

int main()
{
    ios::sync_with_stdio(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C. Paprika and Permutation

题目详情

辣椒粉喜欢排列组合。她有一个数组 a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an。她想让数组成为整数 1 到 n 的排列。

为了实现这个目标,她可以对数组进行操作。在每次运算中她可以选择两个整数i(1≤i≤n)(1≤i≤n)1inx(x>0)x(x>0)xx>0,然后执行ai:=aimodxa_i:=a_i mod xai:=aimodx(即用aia_iai除以x的余数替换aia_iai)。在不同的操作中,选择的 i 和 x 可以不同。

确定使数组成为整数 1 到 n 的排列所需的最少操作次数。如果不可能,则输出-1。

排列是由以任意顺序从 1 到 n 的 n 个不同整数组成的数组。例如,[2,3,1,5,4] 是排列,但 [1,2,2] 不是排列(2 在数组中出现两次),[1,3,4] 也不是排列排列(n=3 但数组中有 4 个)。

输入

每个测试包含多个测试用例。第一行包含一个整数 t(1≤t≤104)t (1≤t≤10^4)t(1t104)——测试用例的数量。测试用例的描述如下。

每个测试用例的第一行包含一个整数 n(1≤n≤105)n (1≤n≤10^5)n(1n105)

每个测试用例的第二行包含 n 个整数 a1,a2,...,an。(1≤ai≤109)a_1,a_2,...,a_n。 (1≤a_i≤10^9)a1,a2,...,an(1ai109)

保证所有测试用例的 n 总和不超过 2⋅1052⋅10^52105

输出

对于每个测试用例,输出使数组成为整数 1 到 n 的排列所需的最少操作次数,如果不可能,则输出 -1。

解题思路:

关键:如果查询(a,b,c)的结果≠查询(b,c,d)的结果,由于b和c是共同的,玩家a和d有不同的角色。 此外,如果查询的结果 (a,b,c) = 1,则玩家 a 是船员(玩家 d 是冒名顶替者),反之亦然。

第一步是查询玩家 (1,2,3), (2,3,4), …, (n−1,n,1), (n,1,2)。

如果任意两个相邻查询(或查询 (1,2,3) 和 (n,1,2))的结果不同,我们立即知道只包含在一个查询中的两个玩家的角色——一个是 队友,一个是冒名顶替的。 由于冒名顶替者 k 和船员 nk 的数量满足 k>n3 和 nk>n3,因此必须存在一对不同的相邻查询。

在我们知道一名船员和一名冒名顶替者(让我们称他们为 a、d)后,我们可以查询这两名玩家与其他玩家中的每一个。 如果查询 (a,d,x)(1≤x≤n,x≠a 和 x≠d)返回 0,则玩家 x 是冒名顶替者,否则玩家 x 是队友。

总共使用了 2n−2 个查询。

coed:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;

const int N=1e6+5;
int n,tot;
int a[N],ocr[N];
inline void solve(){
    cin >>n;
    for (int i=1;i<=n;i++) ocr[i]=0;
    tot=0;
    for (int i=1,t;i<=n;i++){
        cin >>t;
        if (t<=n&&!ocr[t]) ocr[t]=1;
        else a[tot++]=(t-1)/2;
    }
    int ans=tot;
    sort(a,a+tot);
    for (int i=n;i>=1;i--){
        if (ocr[i]) continue;
        else {
            if (a[--tot]<i){
                cout <<"-1\n";
                return;
            }
        }
    }
    cout <<ans<<'\n';
}

int main(){
    ios::sync_with_stdio(0);
    int t;
    cin >> t ;
    while(t--){
         solve();
    }
    return 0;
}

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eternity_GQM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值