Codeforces Round #739 (Div. 3) (7/7)


感觉这场的难度区分度挺高的,前面三道题手速题,后面还是有点难度(对我这种小白来说),运气好排进前1000,有点意思~~。

A. Dislike of Threes

题意: 将大于0的整数中,去掉 能被3整除的数以3结尾的数,从小到大排成一个序列,输出这个序列的第k个元素。

能被3整除的数:i % 3 != 0
以3结尾的数:i % 10 != 3

#include<bits/stdc++.h>
using namespace std;
const int N=10100;
int a[N];
void ok(){
    int cnt = 0;
    for (int i = 1; i <= 3000; i++) {
        if (i % 3 != 0 && i % 10 != 3) {
            a[++cnt] = i;
        }
    }
}
int main(){
    int _;
    cin >> _;
    ok();
    while(_--){
        int k;
        cin >> k;
        cout << a[k] << endl;
    }
    return 0;
}

B. Who’s Opposite?

题意: 一些人围成一个圈,(人数为偶数),这些人从数字1开始顺时针编号,每个人可以透过圆的中心看对面的人。(其中箭头表示谁在看谁),输入三个数,a, b, c;
其中:a看向b,求c看向的是谁?

题解: 通过观察,这个圆的最大数是:max = abs(a-b)×2,那么需要保证a,b,c都要小于等于这个最大数,如果存在大于max的数,则不满足题意,输出-1。
设对面的数是x,有两种情况:
① c > x
② c < x
But都可以归结为: ( ( c − 1 ) + ( m a x / 2 ) )    %    t + 1 ((c-1) + (max / 2)) \;\% \;t + 1 ((c1)+(max/2))%t+1

#include<bits/stdc++.h>
using namespace std;
const int N=10100;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int _;
    cin >> _;
    while(_--){
        int a, b, c;
        cin >> a >> b >> c;
        int maxn = abs(a - b) * 2;
        if (a > maxn  || b > maxn  || c > maxn ) cout << -1 << endl;
        else cout << (c - 1 + (maxn  / 2)) % maxn  + 1 << endl;
    }
    return 0;
}

C. Infinity Table

题意: 构造一个无限行无限列的表,构造方法如图所示,给出一个k,求出这个k的坐标位置。

通过观察发现,所有的完全平方数,均在最左边的一列,所以分类讨论:
存一个int sk = sqrt(k); 其中 (sk 是 sqrt(k)的缩写,这样好理解点)
s k ∗ s k = = k sk * sk == k sksk==k,证明 k 这个数恰好是完全平方数,那么这个数的位置就在 ( s q r t ( k ) , 1 ) (sqrt(k), 1) (sqrt(k),1) ( s k , 1 ) (sk, 1) (sk,1),如下图所示:

k − s k ∗ s k = = s k + 1 k - sk * sk == sk + 1 ksksk==sk+1 ,证明 k 这个数恰好在,下一行下一列,即1的斜对角位置,如下图所示。

k − s k ∗ s k ≤ s k k - sk * sk ≤ sk ksksksk ,证明k这个数在第sk列,如下图所示:

k − s k ∗ s k > s k k - sk * sk > sk ksksk>sk ,证明k这个数在第sk行,如下图所示:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=10100;
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int _;
    cin >> _;
    while(_--){
        int k, sk;
        cin >> k;
        sk = sqrt(k);
        int r, c;
        if (sk * sk == k) {
            r = sk;
            c = 1;
        } else if (k - sk * sk == sk + 1) {
            r = sk + 1;
            c = sk + 1;
        } else if (k - sk * sk <= sk) {
            r = k - sk * sk;
            c = sk + 1;
        } else {
            r = sk + 1;
            c = sk + 1 - (k - sk * sk - sk - 1);
        }
        cout << r << ' ' << c << endl;
    }
    return 0;
}

D. Make a Power of Two

题意: 给定一个整数n,每一次可以选择一下一项执行:

  1. 删除这个数任一数位的数字。(运算前的数字只有一个数字,运算后的数字是“空”,这是可以接受的)
  2. 向右加一位。

注意,如果在删除某个数字后,它包含前导零,则不会删除。例如,如果你从数字301中删除数字3,结果就是数字01(而不是1)。

需要执行最少的操作数,使得数字为2的任意次方,结果必须没有前导零。
样例:
如果n=1052,需要操作2次,往右边加4,删掉5.
如果n=8888,需要操作3次,连续删掉3次8

思路: ,删除任意一位数,加上任意一位数,貌似都与2的幂没什么关系,所以通过字符串的角度来思考这个问题。

n的范围是: 1 ≤ n ≤ 1 0 9 1≤n≤10^9 1n109,那么字符串的长度便是: l e n ≤ 9 len≤9 len9,对于任意字符串,想要变成2的幂,最多可以通过len+1次操作使之变成2的幂,即全部删完,添加一个2。所以字符串的范围最大不会超过1e18,通过计算是大于 2 60 2^{60} 260的, 比赛的时候,粗略估计了一下,以为是 2 62 2^{62} 262~ 2 63 2^{63} 263,就往大了开 。

再去从左往右遍历字符串,比如说1052,就匹配102,对应匹配到1024,再往后面加上一个4

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define int long long
using namespace std;
int l[100];
int mi2[100];
int n;
char ch[100][50];
char t[50];
char s[50];
void init()
{
    mi2[0] = 1;
    for (int i = 1; i <= 62; i++)
        mi2[i] = mi2[i - 1] << 1;
    for (int i = 0; i <= 62; i++)
    {
        while (mi2[i])
        {
            t[++l[i]] = mi2[i] % 10 + '0';
            mi2[i] /= 10;
        }
        for (int j = 1; j <= l[i]; j++)
            ch[i][l[i] - j + 1] = t[j];
    }
    char mi63[40] = "9223372036854775808";
    char mi64[40] = "18446744073709551616";
    for (int i = 0; i <= 30; i++)
    {
        ch[63][i + 1] = mi63[i];
        ch[64][i + 1] = mi64[i];
    }
    l[63] = strlen(mi63);
    l[64] = strlen(mi64);
}
int ck(int x)
{
    int idx1 = 0, idx2 = 0;
    while (idx1 < n && idx2 < l[x])
    {
        while (s[idx1 + 1] != ch[x][idx2 + 1] && idx1 < n && idx2 < l[x])
            idx1++;
        if (s[idx1 + 1] == ch[x][idx2 + 1] && idx1 < n && idx2 < l[x])
        {
            idx1++;
            idx2++;
        }
    }
    int res = (n - idx2) + l[x] - idx2;
    return res;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    init();
    int _;
    cin >> _;
    while (_--)
    {
        memset(s, 0, sizeof s);
        cin >> s + 1;
        n = strlen(s + 1);
        int ans = n + 1;
        for (int i = 0; i <= 64; i++)
        {
            ans = min(ans, ck(i));
        }
        cout << ans << endl;
    }
    return 0;
}

E. Polycarp and String Transformation

P先生有一个字符串s,P先生执行以下操作,知道字符串s为空(t最初是一个空字符串)
在字符串t的右边加上字符串s,即t=t + s

以第一个例子为例:
input:abacabaaacaac
output:abacaba bac
输出中的第二个字符串bac指的是:
input的字符串从右往左每个字符出现的顺序即 cab 的反转

这个是求得output中第一个字符串的长度。
for (int i = 0; i < lens1; i++) len += cnt[s1[i] - 'a'] / (i + 1);

后面就直接暴力删字符就行了
最后看是否跟原来输入的s相等,即可

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

int _;
int cnt[26];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> _;
    while (_--)
    {
        memset(cnt, 0, sizeof cnt);

        string s;
        cin >> s;
        int lens = s.size();
        string s1;
        for (int i = lens - 1; i >= 0; i--)
        {
            cnt[s[i] - 'a']++;
            if (cnt[s[i] - 'a'] == 1)
                s1 += s[i];
        }

        int lens1 = s1.size();
        reverse(s1.begin(), s1.end());
        int len = 0;
        for (int i = 0; i < lens1; i++)
        {
            len += cnt[s1[i] - 'a'] / (i + 1);
            // cout << i << ' ' << len << endl;
        }

        string ss = s.substr(0, len);
        // cout << ss << endl;
        string str1 = ss, str2 = ss;

        for (int i = 0; i < lens1; i++)
        {
            string str3;
            for (int j = 0; j < str1.size(); j++)
            {
                if (str1[j] != s1[i])
                    str3 += str1[j];
            }
            str2 += str3;
            str1 = str3;
        }
        if (str2 == s)
            cout << ss << ' ' << s1 << endl;
        else
            cout << -1 << endl;
    }
}

F1、F2. Nearest Beautiful Number(明天更,困了)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000010;
int a[N];
int n, m, k, cnt;
string s, ans;
void dfs(int x, string t) {
    if (cnt > k) return;
    if (t >= ans) return;
    string str = t;
    while (str.length() < n) str += '9';
    if (str < s) return;
    if (x == n) {
        ans = min(ans, t);
        return;
    }
    for (int i = 0; i <= 9; i++) {
        if (++a[i] == 1) cnt++;
        dfs(x + 1, t + (char)(i + 48));
        if (a[i]-- == 1) cnt--;
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _;
    cin >> _;
    while(_--){
        cin >> s >> k;
        for (int i = 0; i <= 10; i++) a[i] = 0;
        n = s.length();
        ans = "999999999";
        cnt = 0;
        dfs(0, "");
        cout << ans << endl;
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值