2020年牛客算法入门课练习赛1题解报告

第一题,链接:https://ac.nowcoder.com/acm/contest/5773/A

题目描述
给你一个长度为n的序列,求序列中第k小数的多少。
输入描述:
多组输入,第一行读入一个整数T表示有T组数据。
每组数据占两行,第一行为两个整数n,k,表示数列长度和k。
第二行为n个用空格隔开的整数。
输出描述:
对于每组数据,输出它的第k小数是多少。
每组数据之间用空格隔开`

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5000005;
int a[maxn];
void quickSelect(int a[],int l,int r,int rank)
{
    
    
    int i=l,j=r,mid=a[(l+r)>>1];
    do{
    
    
        while(a[i]<mid) ++i;
        while(a[j]>mid) --j;
        if(i<=j){
    
    
            swap(a[i],a[j]);
            ++i;
            --j;
        }
    }while(i<=j);
    if(l<=j && rank<=j-l+1) quickSelect(a,l,j,rank);
    if(i<=r && rank>=i-l+1) quickSelect(a,i,r,rank-(i-l));
}
int quick_select(int a[],int n,int k)//第k小
{
    
    
    quickSelect(a,1,n,k);
    return a[k];
}
inline int read(){
    
    
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
    
    
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
    
    
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
int main()
{
    
    
    int t;
    t=read();
    while(t--)
    {
    
    
        int n,k;
        cin>>n>>k;
        for(int i=0;i<n;i++)
            a[i]=read();
        
        cout<<quick_select(a,n,k)<<endl;
    }
    return 0;
}

`
第二题链接:https://ac.nowcoder.com/acm/contest/5773/B

在坐标纸上有N个不重合的点,两两可以连一个线段并延伸成直线,请问在这些直线里最多能选出多少条使得他们两两不平行也不重合。

输入描述:
第1行: 输入1个正整数:N

第2…N+1行:第i+1行是两个用空格隔开的整数,为点i的坐标(Xi,Yi)

输出描述:
输出1个整数,为最多的互不平行的直线数目。

#include<bits/stdc++.h>

using namespace std;

const int N=100003;
int n,k=1,f;
double x[N],y[N],z[N];

int main()
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>x[i]>>y[i];
    }
    for(int i=1;i<=n;i++)
    {
    
    
        for(int j=i+1;j<=n;j++)
        {
    
    
            if(x[i]==x[j])
            {
    
    
                z[++f]=0x3f3f3f3f;
            }
            else
            {
    
    
                z[++f]=(y[i]-y[j])/(x[i]-x[j]);
            }
            
        }
    }
    // sort(z+1,z+1+f);
    // for(int i=2;i<=f;i++)
    // {
    
    
    //     if(z[i]!=z[i-1])
    //     k++;
    // }
    sort(z+1,z+1+f);
    k=unique(z+1,z+1+f)-z-1;
    cout<<k<<endl;
}

第三题链接:https://ac.nowcoder.com/acm/contest/5773/C

题目描述
“丢丢手绢,轻轻地放在小朋友的后面,大家不要告诉她,快点快点抓住她,快点快点抓住她。”
牛客幼儿园的小朋友们围成了一个圆圈准备玩丢手绢的游戏,但是小朋友们太小了,不能围成一个均匀的圆圈,即每个小朋友的间隔可能会不一致。为了大家能够愉快的玩耍,我们需要知道离得最远的两个小朋友离得有多远(如果太远的话牛老师就要来帮忙调整队形啦!)。
因为是玩丢手绢,所以小朋友只能沿着圆圈外围跑,所以我们定义两个小朋友的距离为沿着圆圈顺时针走或者逆时针走的最近距离。
输入描述:
第一行一个整数N,表示有N个小朋友玩丢手绢的游戏。
接下来的第2到第n行,第i行有一个整数,表示第i-1个小朋友顺时针到第i个小朋友的距离。
最后一行是第N个小朋友顺时针到第一个小朋友的距离。
输出描述:
输出一个整数,为离得最远的两个小朋友的距离。

#include<bits/stdc++.h>

using namespace std;
int a[100005];
int n,k,t;



#define ll long long
int main()
{
    
    
    std::ios::sync_with_stdio(false);
    cin>>n;
    ll sum=0;
    for(int i=0;i<n;i++)
    {
    
    
        cin>>a[i];
        sum+=a[i];
    }
    ll ans=0;
    int l=0;
    int g=0;
    ll maxz=0;
    int k=0;
    while(l<n)
    {
    
    
        while((ans+a[g])*2<=sum)
        {
    
    
            ans+=a[g];
            maxz=max(maxz,ans);
            g=(g+1)%(n);
        }
        maxz=max(maxz,sum-(ans+a[g]));
        ans-=a[l];
        l++;
    }
    cout<<maxz<<endl;
}

第四题链接:https://ac.nowcoder.com/acm/contest/5773/D
来源:牛客网

题目描述
我们刚刚学了二分查找——所谓二分查找就是在一堆有序数里找某个符合要求的数。在学完二分查找之后如果让你玩猜数游戏(裁判选定一个目标数字,你说一个数裁判告诉你是高了还是低了直到你猜到那个数)的话,显然你会用二分的方式去猜。
但是不是每一个玩猜数游戏的人都知道二分是最好,甚至一个健忘的玩家都有可能在得到裁判回答的下一个瞬间就忘了他之前问了什么以及裁判的回答),而现在更可怕的是,这个告诉你猜的数是高还是低的裁判他也很健忘,他总是薛定谔的记得这个目标数字,也就是说他的回答有可能出错。我们已经不关心这个不靠谱的游戏本身了,我们更关心裁判这个薛定谔的记得到底有几个是记得…
现在给出这个健忘的玩家的所有猜测和裁判的所有回答,问裁判最多能有多少次是记得目标数字的,即裁判的回复是符合情况的。
输入描述:
第一行包含一个正整数n,表示裁判的回答数(也是玩家的猜数次数)。
接下来n行,首先是猜的数,然后是一个空格,然后是一个符号。符号如果是“+”说明猜的数比答案大,“-”说明比答案小,“.”说明猜到了答案。
输出描述:
包含一个正整数,为裁判最多有多少个回答是正确的。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int inf=INT_MAX;
int a[1000005];
char s[1000005];

int main()
{
    
    
    int n;
    map<int ,int>m;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>a[i]>>s[i];
        if(s[i]=='.') {
    
    m[a[i]]++;m[a[i]+1]--;}
        if(s[i]=='+') {
    
    m[a[i]]--;m[-inf]++;}
        if(s[i]=='-') {
    
    m[inf]--;m[a[i]+1]++;}
        
    }
    int ans=-inf,h=0;
    for(auto x:m)
    {
    
    
        h+=x.second;
        ans=max(h,ans);
    }
    cout<<ans<<endl;
    return 0;
}

第四题链接:https://ac.nowcoder.com/acm/contest/5773/E
来源:牛客网

题目描述
牛客幼儿园的小朋友课间操时间需要按照学号从小到大排队,但是他们太小了只能站成一列顺序却不对,现在幼儿园的阿姨需要帮忙交换小朋友的位置让他们最终有序,阿姨希望能尽快完成交换操作,问最少需要交换多少次,才能使得小朋友们从小到大排好。
注意:每个小朋友的学号不同,但是未必连续,因为可能有小朋友请假了没有来。
输入描述:
第一行一个整数 N。
接下来 N 行每行一个整数,为小朋友们的队列。
输出描述:
一个整数表示小朋友们的最小交换次数。

#include<bits/stdc++.h>
using namespace std;

int getMinSwaps(vector<int> v)
{
    
    
    vector<int> v1(v);   //将A内元素复制到B。
    sort(v1.begin(), v1.end());
    map<int,int> m;
    int len = v.size();
    for (int i = 0; i < len; i++)
    {
    
    
        m[v1[i]] = i;    //  建立每个元素与其应放位置的映射关系
    }
    int loops = 0;      //  循环节个数
    vector<bool> flag(len, false); //初始化
    //找出循环节的个数
    for (int i = 0; i < len; i++)
    {
    
    
        if (!flag[i])
        {
    
    
            int j = i;
            while (!flag[j])     //对环处理
            {
    
    
                flag[j] = true;
                j = m[v[j]];    //原序列中j位置的元素在有序序列中的位置
            }
            loops++;
        }
    }
    return len - loops;
}
vector<int> v;
int main()
{
    
    
    int n,k;
    cin>>n;
    while(n--){
    
    
        cin>>k;
        v.push_back(k);
    }
    int num = getMinSwaps(v);
    cout<<num<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46264636/article/details/106430838