2020年牛客算法入门课练习赛1

A 第K小数

题目描述:

给你一个长度为n的序列,求序列中第k小数的多少。

思路:

因为数字比较小,用桶排序,可以做到O(n)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=5e6+10;
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 t;
int a[N];
int gs[N];
int main()
{
    scanf("%d",&t);
    while(t--) {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) gs[i]=0;
        for(int i=1;i<=n;i++) {
            a[i]=read();
            gs[a[i]]++;
        }   
        int pos=1,ans=1;
        while(k) {
            if(gs[pos]<k) {
                k-=gs[pos];
                pos++;
            }else {
                ans=pos;
                k=0;
            }
        }
        printf("%d\n",ans);
    }

}

B 不平行的直线

题目描述:

个点,两两形成一条直线,问最多有多少条不平行且不重合的直线

思路:

使用 去重即可,对于一条直线直接保存斜率的分子分母 ,化成最简并且 同号即可,时间复杂度

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=500;
int gcd(int a,int b) {
    return b==0?a:gcd(b,a%b);
}
int x[N],y[N];
set<pair<int,int> >s;
void cl(int a,int b) {
    int X=x[a]-x[b];
    int Y=y[a]-y[b];
    int g=gcd(X,Y);
    X/=g;
    Y/=g;
    if(X<0) X*=-1,Y*=-1;
    s.insert(make_pair(X,Y));
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d%d",&x[i],&y[i]);
    }
    for(int i=1;i<=n;i++) {
        for(int j=i+1;j<=n;j++) {
            cl(i,j);
        }
    }
    printf("%d\n",int(s.size()));
}

C 丢手绢

题目描述:

个人,围成一圈,已知相邻人的距离,求最远的两个人的距离

思路:

预处理顺时针距离前缀和,可以 求出两个人之间的最短距离,逆时针用总长减去顺时针即可。然后使用尺取法的思想,对于第 个人找到离他最远的 ,那么对于 来说离他最远的一定大于 ,那么就可以 的时间解决了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int d[N];
int sum[N];
int n;
int R;
int dis(int x,int y) {
    return sum[y-1]-sum[x-1];
}
int js(int x,int y) {
    return min(dis(x,y),R-dis(x,y));
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&d[i]);
        R+=d[i];
    }
    for(int i=1;i<=n+1;i++) {
        sum[i]=sum[i-1]+d[i];
    }
    int j=2;
    int ans=0;
    for(int i=1;i<=n;i++) {
        while(j<n&&js(i,j)<=js(i,j+1)) {
            j++;
        }
        //cout<<i<<" "<<j<<endl;
        ans=max(ans,js(i,j));
    }
    printf("%d\n",ans);
}

D 二分

题目描述:

裁判有一个数字 次询问,每一次猜一个数字,返回3种结果, 分别代表猜对了,猜的大了,猜的小了 。问最多有多少个返回结果同时合法。

思路:

可以枚举数字 的值,我们将每次猜的数字和加一、减一都保存下到 数组,可以发现,其中必然存在一个数字可以作为 并且是结果最大。所以枚举数组里的值即可。

假设每次查询数字 ,那么合法的结果个数就是下面三种情况个数的和。

返回 . 的等于 的个数

返回 + 的大于 的个数

返回 - 的小于 的个数

取最大值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
vector<int>v1,v2,v3;
vector<int>v;
int n;
int js(int x) {
    int p1,p2;
    int ans=0;
    p1=lower_bound(v1.begin(),v1.end(),x)-v1.begin();
    p2=upper_bound(v1.begin(),v1.end(),x)-v1.begin();
    ans+=p2-p1;
    p1=upper_bound(v2.begin(),v2.end(),x)-v2.begin();
    p2=v2.size();
    ans+=p2-p1;
    p1=lower_bound(v3.begin(),v3.end(),x)-v3.begin();
    ans+=p1;
    return ans;
}
int main() {
    scanf("%d",&n);
    char c;
    int x;
    for(int i=1;i<=n;i++) {
        scanf("%d %c",&x,&c);
        if(c=='.') v1.push_back(x);
        if(c=='+') v2.push_back(x);
        if(c=='-') v3.push_back(x);
        v.push_back(x+1);
        v.push_back(x);
        v.push_back(x-1);
    }
    sort(v1.begin(),v1.end());
    sort(v2.begin(),v2.end());
    sort(v3.begin(),v3.end());
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    int ans=0;
    for(int a:v) {
        ans=max(ans,js(a));
    }
    printf("%d\n",ans);
}

E 交换

题目描述:

n个数字,要求从小到大排列,问最少交换两个数字几次。

思路:

可以发现,对于一个 这种的类型的交换,需要的是点个数-1次交换,那么对于这个序列来说,我们只要计算出所有这种类型的交换集,然后答案就是总点数-交换集的个数。

对于该问题,可以转化成图论来解决,即求环的个数。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
int a[N],b[N];
bool vis[N];
vector<int>v;
int getid(int x) {
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
vector<int>e[N];
void dfs(int u) {
    vis[u]=1;
    for(int a:e[u]) {
        if(!vis[a]) {
            dfs(a);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=1;i<=n;i++) {
        b[i]=getid(a[i]);
    }
    for(int i=1;i<=n;i++) {
        e[i].push_back(b[i]);
    }
    int ans=0;
    for(int i=1;i<=n;i++) {
        if(!vis[i]) {
            ans++;
            dfs(i);
        }
    }
    printf("%d\n",n-ans);
}
全部评论

相关推荐

03-01 19:30
已编辑
南京大学 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
9672次浏览 89人参与
# 你的实习产出是真实的还是包装的? #
1742次浏览 40人参与
# MiniMax求职进展汇总 #
23852次浏览 308人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7464次浏览 43人参与
# 简历第一个项目做什么 #
31568次浏览 330人参与
# 重来一次,我还会选择这个专业吗 #
433365次浏览 3926人参与
# 巨人网络春招 #
11304次浏览 223人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
186990次浏览 1122人参与
# 牛客AI文生图 #
21408次浏览 238人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152293次浏览 887人参与
# 研究所笔面经互助 #
118873次浏览 577人参与
# 简历中的项目经历要怎么写? #
310079次浏览 4194人参与
# AI时代,哪些岗位最容易被淘汰 #
63432次浏览 804人参与
# 面试紧张时你会有什么表现? #
30490次浏览 188人参与
# 你今年的平均薪资是多少? #
213013次浏览 1039人参与
# 你怎么看待AI面试 #
179875次浏览 1235人参与
# 高学历就一定能找到好工作吗? #
64313次浏览 620人参与
# 你最满意的offer薪资是哪家公司? #
76438次浏览 374人参与
# 我的求职精神状态 #
447988次浏览 3128人参与
# 正在春招的你,也参与了去年秋招吗? #
363256次浏览 2637人参与
# 腾讯音乐求职进展汇总 #
160585次浏览 1111人参与
# 校招笔试 #
470477次浏览 2964人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务