百度松果菁英班“天天向上”擂台赛进阶题第一期题解

碰碰车

可以将题目中的一条直线抽象化为一维数轴,将每辆小车的位置按数轴上的坐标点来进行模拟。利用数对pair来对于每辆小车的详细信息进行存储,由于小车与小车之间相遇之后方向会发生改变且掉头时间忽略,初始小车位于数轴的某一位在变化过后依旧位于数轴的某一位,因此可以只考虑小车位置而不必考虑小车的方向。

所有小车的初始位置依次按照坐标升序排列,而后计算出这些小车分别在t秒之后的位置,再按照升序排列,t秒之后,位置相同的小车即为相遇,扫描一遍数对数组将此类特殊小车的方向置为0即可。利用map将初始位置(排序后)与最终位置形成一一对应的映射关系,而后对于初始位置(未排序)的小车输出其对应映射即可。

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
typedef pair<int,int> PII;
vector<PII> A,B,O;
map<PII,PII> Q;
int main()
{
    int n,t;
    cin >> n >> t;
    for(int i = 1;i <= n;i ++ )
    {
        int idx,direction;
        cin >> idx >> direction;
        A.push_back({idx,direction});
    }
    O = A;
    B = A;
    sort(A.begin(),A.end());
    for(int i = 0;i < B.size();i ++ )
    {
        if(B[i].second == -1)B[i].first -= t;
        else if(B[i].second == 1)B[i].first += t;
    }
    sort(B.begin(),B.end());
    for(int i = 0;i < B.size();i ++ )
    {
        if(B[i].first == B[i + 1].first)
        {
            B[i].second = 0;
            B[i + 1].second = 0;
        }
    }
    for(int i = 0;i < A.size();i ++ )Q[A[i]] = B[i];
    for(int i = 0;i < O.size();i ++ )
    {
        PII t = Q[O[i]];
        cout << t.first << ' ' << t.second << endl;
    }
    return 0;
}

序列操作

由于其为单调非递减数列,因此第一个数即为最小的数,仅仅只需要判断第一个数满不满足等于target即可,题目所给条件1和2直接转换为

a[i] != k && a[i] != a[i + 1]

综上所述,答案即为

#include <iostream>
using namespace std;
const int N = 1000000 + 10;
int a[N];
int main( )
{
    int n,k,ans = 0;
    cin >> n >> k;
    for(int i = 1;i <= n;i ++ )cin >> a[i];
    while(a[1] != k)
    {
        for(int i = 1;i <= n;i ++ )
        {
            if(a[i] != k && a[i] != a[i + 1])a[i] ++ ;
        }
        ans ++ ;
    }
    cout << ans << endl;
    return 0;
}

一秒成零

简单while循环即可

#include <iostream>
using namespace std;
int ans = 0;
int main()
{
    int n;
    cin >> n;
    while(n > 0)
    {
        if(n & 1)n -- ;
        else n /= 2;
        ans ++ ;
    }
    cout << ans << endl;
    return 0;
}

小码哥的计划表

可以累加求取总的题目数sum,若是sum不满足在[L * n,R * n]合理区间内,那么题目必定是无解的,输出-1即可。若是sum位于合理区间,则对于每天的做题数进行检查,分别设置sub(减去后能变合理)和add(加上后能变合理),并求取其二者max即可

#include <iostream>
using namespace std;
const int N = 1000000 + 10;
int a[N],sum = 0,L,R;
int main()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i ++ )
    {
        cin >> a[i];
        sum += a[i];
    }
    int l,r;
    cin >> l >> r;
    L = l * n,R = r * n;
    if(sum >= L && sum <= R)
    {
        int add = 0,sub = 0;
        for(int i = 1;i <= n;i ++ )
        {
            if(a[i] >= l && a[i] <= r)continue;
            else if(a[i] > r)sub += a[i] - r;
            else if(a[i] < l)add += l - a[i];
        }
        cout << max(add,sub) << endl;
    }
    else cout << -1 << endl;
    return 0;
}

九次九日九重色

动态规划,f[i]表示字符串的前i位是否能够由P集合中的子串拼接而来

由于枚举的 i 表示是第几个字母,所以字符串的下标是 i-1 ,所以截取字符串的初始位置为 i-1-l+1=i-l

#include <iostream>
#include <string>
using namespace std;
string s[210];
string str;
bool f[200005]; 
int main()
{
    int k;
    string ss;
    for (k = 1;; k++)
    {
        cin >> ss;
        if (ss == ".")break;
        s[k] = ss;
    }
    while (cin >> ss)str += ss; 
    f[0] = 1;
    int ans = 0;
    int len = str.size();
    for (int i = 1; i <= len; i++)
    {
        for (int j = 1; j < k; j++)
        {
            int l = s[j].size();
            if (i >= l && f[i - l] && s[j] == str.substr(i - l, l))
            {
                f[i] = 1;
                ans = i;
                break;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

寻找串

字符串长度从最长开始枚举,依次递减。检查是否有长度相同且出现两次的字符串,若有则直接输出,程序结束,若无则在for循环运行结束时,执行0无解输出

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
    string s;
    cin >> s;
    for(int i = s.size() - 1;i >= 1;i -- )
    {
        vector<string> Q;
        for(int j = 0;j < s.size() - i;j ++ )
        {
            string t = s.substr(j,i);
            Q.push_back(t);
        }
        int nums = Q.size();
        sort(Q.begin(),Q.end());
        Q.erase(unique(Q.begin(),Q.end()),Q.end());
        if(nums != Q.size())
        {
            cout << i << endl;
            return 0;
        }
    }
    cout << 0 << endl;
    return 0;
}

排队

简单模拟不再赘述

#include <iostream>
using namespace std;
int main( )
{
    int n,t;
    cin >> n >> t;
    string s;
    cin >> s;
    int cnt = 0;
    while(cnt != t)
    {
        for(int i = 0;i < s.size();i ++ )
        {
            if(s[i] == 'B' && s[i + 1] == 'G')
            {
                swap(s[i],s[i + 1]);
                i ++ ;
            }
        }
        cnt ++ ;
    }
    cout << s << endl;
    return 0;
}

邮箱地址

依次写出检查username,hostname,resource的check函数即可

bool check1(string s)
{
    int l = s.size();
    if(!(l >= 1 && l <= 16))return false;//判断长度是否合理
    for(int i = 0;i < s.size();i ++ )//检查内容是否合理
    {
        if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= '1' && s[i] <= '9') || (s[i] == '_'))continue;
        else return false;
    }
    return true;
}
bool check2(string s)
{
    int l = s.size();
    if(!(l >= 1 && l <= 32))return false;//判断长度是否合理
    if(s[0] == '.' || s[s.size() - 1] == '.')return false;//检查开头和结尾是否合理
    for(int i = 0;i < s.size();i ++ )//检查是否有两个点连在一起
    {
        if(s[i] == '.' && s[i + 1] == '.')return false;
    }
    string t;//储存子段
    for(int i = 0;i < s.size();i ++ )
    {
        if(s[i] != '.')t += s[i];
        else  
        {
            if(!check1(t))return false;//子段不合法
            t = "";//子段清空
        }
        if(t.size() > 16)return false;//子段长度非法
    }
    //在运行结束之后还会存储一个待检查的子段
    if(t != "" && !check1(t))return false;//检查该子段是否为空或者不符合子段条件
    return true;
}
bool check3(string s)
{
    if(s.size() == 0)return false;//斜杠一旦存在,resource不能为空
    for(int i = 0;i < s.size();i ++ )//检查内容
    {
        if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= '1' && s[i] <= '9') || (s[i] == '_'))continue;
        else return false;
    }
    return true;
}

@为必须项,若无则非法,取得username可用string的substr进行字符串截取,substr(a,b)截取以a为下标开始的,长度为b的子串,由于字符串下标是从0开始的,因此subsr(0,pos1)截取的即为[0,pos1)区间的子串,也就是username。查/是否存在,若存在hostname即为substr(pos1 + 1,pos2 - pos1 - 1),resource即为substr(pos2 + 1),当substr仅仅有一个参数的时候,截取的为该参数后的所有剩余字符;若/不存在,则hostname为substr(pos1 + 1);

综上所述

#include <iostream>
#include <cstring>
using namespace std;
bool check1(string s)
{
    int l = s.size();
    if(!(l >= 1 && l <= 16))return false;//判断长度是否合理
    for(int i = 0;i < s.size();i ++ )//检查内容是否合理
    {
        if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= '1' && s[i] <= '9') || (s[i] == '_'))continue;
        else return false;
    }
    return true;
}
bool check2(string s)
{
    int l = s.size();
    if(!(l >= 1 && l <= 32))return false;//判断长度是否合理
    if(s[0] == '.' || s[s.size() - 1] == '.')return false;//检查开头和结尾是否合理
    for(int i = 0;i < s.size();i ++ )//检查是否有两个点连在一起
    {
        if(s[i] == '.' && s[i + 1] == '.')return false;
    }
    string t;//储存子段
    for(int i = 0;i < s.size();i ++ )
    {
        if(s[i] != '.')t += s[i];
        else  
        {
            if(!check1(t))return false;//子段不合法
            t = "";//子段清空
        }
        if(t.size() > 16)return false;//子段长度非法
    }
    //在运行结束之后还会存储一个待检查的子段
    if(t != "" && !check1(t))return false;//检查该子段是否为空或者不符合子段条件
    return true;
}
bool check3(string s)
{
    if(s.size() == 0)return false;//斜杠一旦存在,resource不能为空
    for(int i = 0;i < s.size();i ++ )//检查内容
    {
        if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= '1' && s[i] <= '9') || (s[i] == '_'))continue;
        else return false;
    }
    return true;
}
int main()
{
    string str;
    getline(cin,str);
    string a,b,c;
    int pos1 = str.find("@");
    if(pos1 == -1)
    {
        cout << "NO" << endl;
        return 0;
    }
    a = str.substr(0,pos1);
    int pos2 = str.find("/");
    if(pos2 == -1)b = str.substr(pos1 + 1);
    else 
    {
        b = str.substr(pos1 + 1,pos2 - pos1 - 1);
        c = str.substr(pos2 + 1);
        if(!check3(c))
        {
            cout << "NO" << endl;
            return 0;
        }
    }
    if(check1(a) && check2(b))cout << "YES" << endl;
    else cout << "NO" << endl;
    return 0;
}

换换换

利用map两个容器形成正反映射,肥肠煎蛋

#include <iostream>
#include <map>
using namespace std;
map<int,string> A;
map<string,int> B;
int main()
{
    int n,m,t;
    cin >> n >> m >> t;
    for(int i = 1;i <= n;i ++ )
    {
        string name;
        cin >> name;
        A.insert({i,name});
        B.insert({name,i});
    }
    while(t -- )
    {
        int a,b;
        cin >> a >> b;
        string a_name = A[a];
        string b_name = A[b];
        swap(B[A[a]],B[A[b]]);
        swap(A[a],A[b]);
    }
    while(m -- )
    {
        string name;
        cin >> name;
        cout << B[name] << endl;
    }
    return 0;
}

可怜的小码哥

注意数据范围要开long long,利用set集合自动去重且集合内元素默认升序排序的特性,将所给素数存入set集合当中,只要set集合的大小小于等于m,则不断的对于其进行乘法运算操作,直至集合中丑数的个数满足要求,利用cnt当作计数器进行计数,使用迭代器进行遍历set集合,取第m个输出即可

#include <iostream>
#include <set>
#include <cmath>
using namespace std;
typedef long long ll;
set<ll> A;
int main()
{
    ll MAX = pow(2,31) - 1;
    int n,m;
    cin >> n >> m;
    for(int i = 1;i <= n;i ++ )
    {
        int num;
        cin >> num;
        A.insert(num);
    }
    while(A.size() <= m)
    {
        for(set<ll>::iterator i = A.begin();i != A.end();i ++ )
        {
            for(set<ll>::iterator j = i;j != A.end();j ++ )
            {
                ll num = (*i) * (*j);
                if(num > MAX)break;
                else A.insert(num);
            }
        }
    }
    int cnt = 0;
    for(set<ll>::iterator i = A.begin();i != A.end();i ++ )
    {
        cnt ++ ;
        if(cnt == m)
        {
            cout << *i << endl;
            break;
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

计科土狗

谢谢家人们

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

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

打赏作者

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

抵扣说明:

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

余额充值