2020牛客国庆集训day4

本文档详细解析了四个编程题目,涉及字符串比较、最长等差数列、乘客下车操作优化及字符串全排列问题。通过模拟题展示思路并提供了C++代码实现,适合深入理解算法和数据结构在实际编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A 模拟题
思路:将数字和字母都分成独立项分别讨论,其中数字项需要注意连续数字字符需要转化成一个数字项进行判断

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;

string s0,sn;
const int N=1e5+10;
int a[N],b[N];//字母0,数字1

bool solve()//false- true+
{
    int i=0,j=0;
    for(;i<s0.length()&&j<sn.length();i++,j++){
        //cout<<i<<' '<<j<<endl;
        if(a[i]==0&&b[j]==0){//两个都是字母
            if(sn[j]<s0[i])return false;
            if(sn[j]>s0[i])return true;
        }else if(a[i]==1&&b[j]==1){//两个都是数字
            int num1=0,num2=0;
            while(a[i]==1){
                num1=num1*10+s0[i]-'0';
                i++;
            }
            i--;
            while(b[j]==1){
                num2=num2*10+sn[j]-'0';
                j++;
            }
            j--;
            //cout<<num1<<' '<<num2<<endl;
            if(num1>num2)return false;
            if(num1<num2)return true;
        }else if(a[i]==1&&b[j]==0){
            return true;
        }else if(a[i]==0&&b[j]==1){
            return false;
        }
    }
    //cout<<i<<' '<<j<<endl;
    if(i<s0.length())return false;
    if(j<sn.length())return true;
    return true;
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    cin>>s0;
    for(int i=0;i<s0.length();i++){
        if(isalpha(s0[i]))a[i]=0;
        else a[i]=1;
    }
    while(t--){
        cin>>sn;
        memset(b,0,sizeof(b));
        for(int i=0;i<sn.length();i++){
            if(isalpha(sn[i]))b[i]=0;
            else b[i]=1;
        }
        if(solve())cout<<"+"<<endl;
        else cout<<"-"<<endl;
    }
    return 0;
}

B
题意:求最长等差数列的长度
思路:dp,首先很显然输出的最长长度最小也要是2,对数组从前往后遍历,每次取出一个公差对dp数组进行更新,取最大的长度

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=5e3+10;
int a[N],dp[N][N];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+n+1);
    int ans=0;
    for(int i=1;i<=n;i++){
        int k=i-1;
        for(int j=i+1;j<=n;j++){
            dp[i][j]=2;
            int d=a[j]-a[i];
            while(k>=1&&a[i]-a[k]<d)k--;
            if(k==0||a[i]-a[k]!=d)continue;
            dp[i][j]=max(dp[i][j],dp[k][i]+1);
            ans=max(ans,dp[i][j]);
        }
    }
    if(ans==0)ans=2;
    cout<<ans<<endl;
    return 0;
}

C 思维题
题意:求使得所有乘客都下车的最小操作数
思路:贪心,求出离出口最远的乘客所需的操作数再加上不能人挤人导致的时间延后数即所求答案

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

const int N=1e6+10;
int a[N];

bool cmp(int a,int b)
{
    return a>b;
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int r,s,p,x,y;
    cin>>r>>s>>p;
    for(int i=0;i<p;i++){
        cin>>x>>y;
        x--,y--;//使其下标为0
        if(y>=s)y++;
        a[i]=abs(x-r)+abs(y-s);//每个坐标对应到出口的距离
    }
    sort(a,a+p,cmp);
    int ans=0;
    for(int i=0;i<p;i++)ans=max(ans,a[i]+i);
    cout<<ans<<endl;
    return 0;
}

J 暴搜题
题意:将字符串用空格分隔开使得它成为某个数的全排列
思路:因为n只到50,所以所有数要么是一位数,要么是两位数,位数没有别的可能,所以可以dfs暴搜,从字符串第一位开始先假设当前对应数字是一位数,继续往后遍历,当遍历完一遍不是全排列或者出现前导0的时候不满足条件开始回溯,继续dfs,一直到找到一组符合条件的答案就退出

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=55;
int n,path[N],tt;//path存储路径
bool vis[N];
bool flag=false;
string s;

void dfs(int u)
{
    if(flag)return;
    if(u>=s.size()){
        for(int i=1;i<=tt;i++)cout<<path[i]<<' ';
        cout<<endl;
        flag=true;
        return;
    }
    if(s[u]-'0'==0)return;
    //枚举一位数情况
    if(!vis[s[u]-'0']){
        vis[s[u]-'0']=true;
        path[++tt]=s[u]-'0';
        dfs(u+1);
        tt--;
        vis[s[u]-'0']=false;
    }
    //枚举两位数情况
    int num=(s[u]-'0')*10+s[u+1]-'0';
    if(u+1<s.size()){
        if(!vis[num]&&num<=n){
            vis[num]=true;
            path[++tt]=num;
            dfs(u+2);
            tt--;
            vis[num]=false;
            
        }
    }
}

int main()
{
    cin>>s;
    if(s.size()<10)n=s.size();
    else n=(s.size()-9)/2+9;
    dfs(0);
    return 0;
}
### 关于2020寒假算法基础集训营中的欧几里得算法 在2020年的寒假算法基础集训营中,确实存在涉及欧几里得算法的相关题目。具体来说,在第四场竞赛的第一题即为“A. 欧几里得”,该题目的核心在于利用扩展欧几里得定理来解决问题[^5]。 #### 扩展欧几里得算法简介 扩展欧几里得算法主要用于求解形如 ax + by = gcd(a, b) 的线性不定方程的一组特解(x,y),其中gcd表示最大公约数。此方法不仅能够计算两个整数的最大公因数,还能找到满足上述条件的具体系数x和y。 对于给定的数据范围较小的情况可以直接通过递归来实现;而对于较大数据则需考虑效率优化问题。下面给出了一段基于C++语言编写的用于解决此类问题的模板代码: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; // 定义全局变量存储结果 int x, y; void ex_gcd(int a, int b){ if(b == 0){ x = 1; y = 0; return ; } ex_gcd(b, a % b); int tmp = x; x = y; y = tmp - (a / b) * y; } ``` 这段程序实现了经典的扩展欧几里得算法逻辑,并且可以作为处理类似问题的基础工具函数调用。 #### 实际应用案例分析 回到原题本身,“A. 欧几里得”的解答思路就是先预处理斐波那契数列前若干项数值存入数组`a[]`内以便快速查询,之后针对每一次询问直接输出对应位置处两相邻元素之和即可得出最终答案。这实际上巧妙运用到了广为人知的裴蜀定理——任意一对互质正整数都可由它们自身的倍数组合而成,而这里正是借助了这一性质简化了解决方案的设计过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值