Codeforces Round #739 (Div. 3)

比赛链接

A.Dislike of Threes

题意:

特殊序列:不带有 可以被 3 整除的数 和 以 3 结尾的数
eg:1,2,4,5,7,8,10,11,14,16,…
输出该序列的第 n 个数

思路:

t 和 n 都不大,直接暴力就能过

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N], p;
void init()
{
    for(int i=1; p <= 1000; i++) {
        if(i%3 == 0 || i%10 == 3) continue;
        else a[++p] = i;
    }
}
int main()
{
    init();
    int t; cin >> t;
    while(t--) {
        int n; cin >> n;
        cout << a[n] << endl;
    }
    return 0;
}

B.Who’s Opposite?

题意:

一群人(偶数)按顺时针编号坐在一个圆桌里,给出 a,b,c
已知 a 和 b 相对,求 c 和谁相对,不存在则输出 -1
例如

思路:

一开始卡题了,懂题意,但思维混乱,一直wa
以下思路借鉴某大佬~

  1. 显然人数总数 n 等于2倍的 abs(a-b)
  2. 如果 a, b, c有任意一个大于 n 的时候,输出 -1
  3. 如果 a 与 b 在 n 中不是相对而坐的,输出 -1
  4. 求 c 相对的人就是第一步求总人数的逆运算
    注:在圆桌上,如果p ≤ n/2,则 p 的对面为 p + n/2,否则 p 的对面为 p - n/2

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t; cin >> t;
    while(t--) {
        int a, b, c; cin >> a >> b >> c;
        if(a > b) swap(a, b);// 使 a < b
        int d = b - a, n = 2 * d;// d,abs(a - b); n,人的总数

        if(a>n || b>n || c>n) cout << -1 << endl;// a or b or c > n,输出-1;
        else if(b != a + d) cout << -1 << endl;// 如果a 与 b 在 n 中不是相对而坐的,输出-1;
        else {
            if(c <= d) cout << c+d << endl;
            else cout << c-d << endl;
        }
    }
    return 0;
}

C. Infinity Table

题意:

有一个排列奇怪的表,求 k 在该表中的坐标(x,y)
表

思路:

找规律,可以用两个一位数组 h[ ]、s[ ] 绘出表的 第一排 和 第一列
每 i 排或每 i 列至多有 i 个数。列,递增;排,递减

  1. 绘制表边(即第一排和第一列)
  2. 特判 k == 1
  3. 找出 k 在第 p 排 或 第 p 列
  4. 判断 k 在 排【k <= (h[p]+p-1)】 还是 列 ,输出(k-h[p]+1, p) or (p, s[p]-k+1)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 32000;// 1e9 在 第 31623排or列
ll h[N], s[N];// long long 防int炸
void init()
{
    h[1] = 1; s[1] = 1;
    int x = 1, y = 3;
    for(int i=2; i<N; i++) {
        h[i] = h[i-1] + x; x += 2;
        s[i] = s[i-1] + y; y += 2;
    }
}
int main()
{
    init();// 绘出 表边(即第一排和第一列)
    
    int t; cin >> t;
    while(t--) {
        int k; cin >> k;
        
        if(k == 1) {// 特判
            printf("1 1\n");
            continue;
        }
        
        int x, y, p=1;// 坐标(x, y) , 第 p 列or排
        for(int i=2; ; i++) {
            if(k >= h[i] && k <= s[i]) {
                p = i;
                break;
            }
        }

        if(k <= (h[p]+p-1)) x = k-h[p]+1, y = p;
        else x = p, y = s[p]-k+1;
        printf("%d %d\n",x, y);
    }
    return 0;
}

D.Make a Power of Two

题意:

给一个 n,每次操作 可以删除其中一位数字 或 在末尾加上一位数字
求变为 2的k次方 的最小的操作步数ans(k为任意正整数)

思路:

这题我原本是不会的,看了别人的题解,此处借鉴,下附链接。

  1. 先考虑数据范围,n最大是1e9,则对每个数的最大操作次数是18次(9次删除9次添加),所以打一个1e18的的2的k次方表
  2. 考虑贪心策略,对于字符串a和b,将a编辑到b可以在a串中找最长的b串并记录,a串中没有找到的b串剩余部分长度则是最后要在末位加的长度
  3. 用两个指针p1,p2分别指向a,b 当a[p1] == b[p2]时,记录相同字符长度,即cnt++
  4. 最终编辑距离 == a串删除的长度 + b串在末位添加的长度 (ans = l1 - cnt + l2 - cnt)

借鉴之地

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 原作者用 a[] 存了 2的0~108次方,就…就很牛
string a2[] = { "1","2","4","8","16","32","64","128","256","512","1024","2048","4096","8192","16384","32768","65536","131072","262144","524288","1048576","2097152","4194304","8388608","16777216","33554432","67108864","134217728","268435456","536870912","1073741824","2147483648","4294967296","8589934592","17179869184","34359738368","68719476736","137438953472","274877906944","549755813888","1099511627776","2199023255552","4398046511104","8796093022208","17592186044416","35184372088832","70368744177664","140737488355328","281474976710656","562949953421312","1125899906842624","2251799813685248","4503599627370496","9007199254740992","18014398509481984","36028797018963968","72057594037927936","144115188075855872","288230376151711744","576460752303423488","1152921504606846976","2305843009213693952","4611686018427387904","9223372036854775808","18446744073709551616","36893488147419103232","73786976294838206464","147573952589676412928","295147905179352825856","590295810358705651712","1180591620717411303424","2361183241434822606848","4722366482869645213696","9444732965739290427392","18889465931478580854784","37778931862957161709568","75557863725914323419136","151115727451828646838272","302231454903657293676544","604462909807314587353088","1208925819614629174706176","2417851639229258349412352","4835703278458516698824704","9671406556917033397649408","19342813113834066795298816","38685626227668133590597632","77371252455336267181195264","154742504910672534362390528","309485009821345068724781056","618970019642690137449562112","1237940039285380274899124224","2475880078570760549798248448","4951760157141521099596496896","9903520314283042199192993792","19807040628566084398385987584","39614081257132168796771975168","79228162514264337593543950336","158456325028528675187087900672","316912650057057350374175801344","633825300114114700748351602688","1267650600228229401496703205376","2535301200456458802993406410752","5070602400912917605986812821504","10141204801825835211973625643008","20282409603651670423947251286016","40564819207303340847894502572032","81129638414606681695789005144064","162259276829213363391578010288128","324518553658426726783156020576256" };
string a[64];// long long类型可以开到2的0~62次方
void init()
{
    ll p = 1;
    for(int i=0; i<63; i++) {
        a[i] = to_string(p);// 将数转换为字符串的形式
        p *= 2;
    }
}
int main()
{
    init();// 初始化 2的幂次方
    
    int t; cin >> t;
    while(t--) {
        string s; cin >> s;
        
        int ans = INT_MAX;// 输出结果
        for(int k=0; a[k].size(); k++) {
            int cnt = 0;// s[p1] 与 a[k].[p2] 相同的个数(下标不对应,仅是遍历s[p1])
            int l1 = s.size(), l2 = a[k].size();
            int p1=0, p2=0;// 遍历用的两个指针
            while(p1 < l1 && p2 < l2) {
                if(s[p1] == a[k][p2]) {
                    p2++; cnt++;
                }
                p1++;
            }
            ans = min(ans, l1-cnt + l2-cnt);// 取最小操作数
        }
        cout << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值