Codeforces Round #739 (Div. 3) 题解(A-F)

Codeforces Round #739 (Div. 3) 题解(A-F)

A. Dislike of Threes

题目大意:

输出第 k k k个既不被 3 3 3整除,尾数也不是 3 3 3的正整数。

解题思路:

因为 1 ≤ k ≤ 1000 1\le k\le 1000 1k1000,所以直接枚举就行了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N];
bool check(int x){
    if(x%3==0||x%10==3) return false;
    return true;
}
int main()
{
    int cnt=0;
    for(int i=1;cnt<=1000;i++)
        if(check(i)) a[++cnt]=i;

    int T;
    scanf("%d",&T);
    while(T--){
        int k;
        scanf("%d",&k);
        printf("%d\n",a[k]);
    }
}

B. Who’s Opposite?

题目大意:

n n n个数字按顺时针围成一个圈,每个数的对立面都会有一个相对的数。现在给出 a a a和跟 a a a相对的数 b b b,问 c c c的相对的数字是多少,如果不存在就输出 − 1 -1 1

解题思路:

通过观察题意可以发现,对于一个 n n n个数字围城的一个圈,相对的两个数之间的差是 n 2 \dfrac{n}2 2n

所以我们可以根据 a a a b b b得到 n n n的大小,如果 a a a b b b c c c大于 n n n就输出 − 1 -1 1

因为 c c c d d d的差值一定是 n 2 \dfrac{n}2 2n,所以 d = c ± n 2 d=c\pm\dfrac{n}2 d=c±2n

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        int n=abs(a-b)*2;
        if(a>n||b>n||c>n) puts("-1");
        else{
            if(c+n/2<=n) printf("%d\n",c+n/2);
            else printf("%d\n",c-n/2);
        }
    }
    return 0;
}

C. Infinity Table

题目大意:

按照题意的规则填数,问第 k k k个数的坐标是多少。

解题思路:

观察之后可以发现,第 i i i轮填 2 × i − 1 2\times i-1 2×i1个数,先从 ( 1 , i ) (1,i) (1,i)开始向下填 i i i个数,再向左填 i − 1 i-1 i1个数。

所以可以通过累加和的形式找到第 k k k个数是第几轮填上去的,再根据剩余的步数判断坐标。

时间复杂度 O ( k ) O(\sqrt k) O(k )

代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        int sum=0,p;
        for(int i=1;;i++){
            if(sum+2*i-1>=n){
                p=i;
                break;
            }
            sum+=2*i-1;
        }
        n-=sum;
        if(n<=p) printf("%d %d\n",n,p);
        else     printf("%d %d\n",p,2*p-n);
    }
    return 0;
}

D. Make a Power of Two

题目大意:

对于给出的整数 n n n,可以采取以下两种操作:

  • 删除任何一位上的数字
  • 从右边添加一位数字

执行操作的过程不允许出现前导零。

问从 n n n变成任何一个 2 2 2的整次幂需要的最少操作步数。

解题思路:

因为 1 ≤ n ≤ 1 0 9 1\le n \le10^9 1n109,所以我们只用考虑 [ 1 , 1 0 18 ] [1,10^{18}] [1,1018]内所有的 2 2 2的整次幂,一共只有 60 60 60个。

所以我们只用计算 n n n转换成将这所有的 2 2 2的整次幂所需的操作步数,取一个最小值就行了。

假设我们要转变的 2 2 2的整次幂是 a a a,我们将 n n n a a a都当做字符串来处理,其中 n n n中能留下的字符数量就是 n n n中子序列与 a a a前缀匹配的最大长度,设这个最大长度为 l e n len len,那么我们所需的操作步骤就是将 n . s i z e ( ) − l e n n.size()-len n.size()len个字符删除,并从右边加上 a . s i z e ( ) − l e n a.size()-len a.size()len个字符。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100;
LL a[N];
void init()
{
    a[0]=1;
    for(int i=1;i<60;i++) a[i]=a[i-1]*2;
}
int check(LL x,LL y){
    string s1=to_string(x),s2=to_string(y);
    int i=0,j=0;
    while(i<s1.size()&&j<s2.size()){
        if(s1[i]==s2[j]) i++,j++;
        else i++;
    }
    return s1.size()-j+s2.size()-j;
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        cin>>n;
        int res=1e9;
        for(int i=0;i<60;i++) res=min(res,check(n,a[i]));
        printf("%d\n",res);
    }
    return 0;
}

E. Polycarp and String Transformation

题目大意:

对于一个字符串 s s s,一直执行以下操作直到字符串为空,字符串 t t t初始是个空字符串:

  • 将字符串 s s s拼接到字符串 t t t的后面,即 t = t + s t=t+s t=t+s
  • 选择一个 s s s中存在的字符 c c c,删除字符串 s s s中所有的c

现在给出字符串 t t t,求原始字符串和删除字符的顺序,如果不存在输出 − 1 -1 1

解题思路:

因为字符串中的字符种类是越来越少的,所以我们可以直接反着遍历一遍字符串 t t t,字符出现的顺序就是删除字符顺序的逆序。

除此之外,我们还可以发现一个性质。

如果一个字符是第一次删除的,这个字符在 t t t中出现的次数 = s =s =s中出现的次数。

如果一个字符是第二次删除的,这个字符在 t t t中出现的次数$ = s 中 出 现 的 次 数 中出现的次数 \times 2$。

. . . . . . ...... ......

同理,我们就可以通过字符在 t t t中出现的次数以及删除顺序就可以得到原字符串 s s s的长度并进一步得到原字符串 s s s

这样我们只需要将现在得到的字符串 s s s按照删除序列执行题意中的操作,看得到的结果与 t t t是否一致,一致的话就输出 s s s o r d e r order order,否则输出 − 1 -1 1

代码:

#include<bits/stdc++.h>
using namespace std;
string t;
int num[26];
string get(string t){
    string res;
    for(int i=t.size()-1;i>=0;i--){
        if(!num[t[i]-'a']) res.push_back(t[i]);
        num[t[i]-'a']++;
    }
    reverse(res.begin(),res.end());
    return res;
}
string check(string s,string order){
    string res=s;
    for(int i=0;i<order.size();i++){
        string temp;
        for(int j=0;j<s.size();j++)
            if(order[i]!=s[j]) temp+=s[j];
        res+=temp;
        s=temp;
    }
    return res;
}
int main()
{
    int T;
    cin>>T;
    while(T--){
        cin>>t;
        memset(num,0,sizeof num);
        string order=get(t);
        int len=0;
        for(int i=0;i<order.size();i++){
            len+=num[order[i]-'a']/(i+1);
        }
        string s=s.substr(0,len);
        if(check(s,order)==t) cout<<s<<" "<<order<<endl;
        else cout<<-1<<endl;
    }
    return 0;
}

F. Nearest Beautiful Number (hard version)

题目大意:

给出两个整数 n n n k k k,输出不小于 n n n的最小k-beautiful数。

k-beautiful数的含义是最多由 k k k个不同的数字构成的整数。

解题思路:

难易版本的区别在于 k k k的范围,简单版本的 1 ≤ k ≤ 2 1\le k\le 2 1k2,因为 k k k比较小,可以直接通过一层循环或者两层循环枚举所有的情况,这里就不再赘述了。

困难版本 k k k的数据范围是 1 ≤ k ≤ 10 1\le k \le 10 1k10,做法的主要思想是贪心,通过让高位的数尽可能小达到整个数尽可能小的目的。

因为如果当前数不满足限制的话,我们就要尝试找一个更大的数,那就意味着必须要有一位比原来大,那么我们就要贪心思考这个问题,每次找到一个尽可能低的位+1,再将后面的数全部置为零,第一次满足条件的时候就是最优解。

有一个要注意的细节,最优解一定是不用进位的,因为就算当前所有位上都填 9 9 9也会比进一位的情况更优,所以要注意别对 9 9 9进行 + 1 +1 +1

代码:

#include<bits/stdc++.h>
using namespace std;
int check(string n){
    set<char> se;
    for(auto c:n) se.insert(c);
    return se.size();
}
int main()
{
    int T;
    cin>>T;
    while(T--){
        string n;
        int k;
        cin>>n>>k;
        while(check(n)>k){
            set<char> se;
            for(int i=0;i<n.size();i++){
                se.insert(n[i]);
                if(se.size()>k){
                    while(n[i]=='9') i--;
                    n[i]++;
                    for(int j=i+1;j<n.size();j++)      n[j]='0';
                    break;
                }
            }
        }
        cout<<n<<endl;
    }
    return 0;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值