2020年牛客算法入门课练习赛1【完结】

感觉题挺不错的,自己也觉得做过很多题了,但是做这一套题还是有的题有些许不会。

第k小数【难度: 简单 / 快排】

在这里插入图片描述
https://ac.nowcoder.com/acm/contest/5773/A

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int a[N],t,n,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(void)
{
    
    
	t=read();;
	while(t--)
	{
    
    
		n=read(); k=read();
		for(int i=1;i<=n;i++) a[i]=read();
		sort(a+1,a+n+1);
		printf("%d\n",a[k]);
	}
	return 0;
}

不平行的直线【难度: 简单 / 数学】

在这里插入图片描述
https://ac.nowcoder.com/acm/contest/5773/B
就是求不同的斜率的数量。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
int gcd(int a,int b) {
    
    return b?gcd(b,a%b):a;}
vector<PII>ve;
int n;
set<PII>st;
int main(void)
{
    
    
	cin>>n;
	for(int i=0;i<n;i++)
	{
    
    
		int a,b; cin>>a>>b;
		ve.push_back({
    
    a,b});
	}
	for(int i=0;i<ve.size();i++)
	{
    
    
		for(int j=i+1;j<ve.size();j++)
		{
    
    
			int a=ve[i].first,b=ve[i].second;
			int c=ve[j].first,d=ve[j].second;
			int s1=c-a,s2=d-b;	
			int temp=gcd(s1,s2);
			st.insert({
    
    s1/temp,s2/temp});
		}
	}
	cout<<st.size()<<endl;
	return 0;
}

丢手绢【难度: 一般 / 取尺法 双指针】

在这里插入图片描述
https://ac.nowcoder.com/acm/contest/5773/C
尺取法,用双指针维护,对于一个点我们的最大结果一定是尽可能的平分。

#include<iostream>
using namespace std;
int a[100010] = {
    
    0};

int main(){
    
    
    int n;
    cin >> n;
    int l = 0, sum = 0;//l在前,i在后
    for(int i = 0; i < n; i++){
    
    
         cin >> a[i];
         sum += a[i];
         }
     int temp = 0;//两者间的距离
     int ans = 0, jin;
     for(int i = 0; i < n; i++)
     {
    
    
     	while(temp < sum / 2)
     	{
    
    //l为前面的
     		temp += a[l % n];//l % n因为是一个圈,在l = n时 又从a[0]开始加起
     		l++;
     	}
     	jin = min(temp, sum - temp);//sum可能为奇数,一般会向下取整,判断较小的那半圈
     	ans = max(ans, jin);//最大值
     	temp -= a[i];
     }
     cout << ans << endl;
     return 0;
}

二分【难度: 中 / 知识点: 差分】

在这里插入图片描述
https://ac.nowcoder.com/acm/contest/5773/D
居然是差分,太秒了。数据范围很大,故直接用map来映射

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int inf=INT_MAX;
map<int,int>mp;
int n=0;
void insert(int l,int r)
{
    
    
	mp[l]++;
	mp[r+1]--;
}
int main(void)
{
    
    
	cin>>n;
	for(int i=0;i<n;i++)
	{
    
    
		int a; char b;
		cin>>a>>b;
		if(b=='.') insert(a,a);//给a这个位置加1
		if(b=='+') insert(-inf,a-1);//给 [-inf,a-1] 这段区间加1
		if(b=='-') insert(a+1,inf-1); //给 [a+1,inf-1]这段区间加1 因为我们的结果是不大于inf的,故是inf-1
	}
	int ans=-1e9,sum=0;
	for(auto i=mp.begin();i!=mp.end();i++)
	{
    
    
		sum+=i->second;
		ans=max(ans,sum);
	}
	cout<<ans<<endl;
	return 0; 
}

交换【难度: 中 / 求环】

在这里插入图片描述
https://ac.nowcoder.com/acm/contest/5773/E
数据范围很大故先离散化一下,再进行。
很经典的一个问题,我们可以用图论的思路来解决。
我们的最终目的是n个自环,cnt用来当前有几个环,n-cnt就是我们还需要的环数,即为答案。

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int s[N],temp[N];
int vis[N];
int n,cnt;
map<int,int>mp;
int main()
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&s[i]),temp[i]=s[i];
    sort(temp+1,temp+n+1);
    for(int i=1;i<=n;i++) mp[temp[i]]=i;
    for(int i=1;i<=n;i++) s[i]=mp[s[i]];//离散化
    for(int i=1;i<=n;i++)
    {
    
    
        if(!vis[s[i]])
        {
    
    
            for(int j=s[i];!vis[j];j=s[j]) vis[j]=1;
            cnt++;
        }
    }
    cout<<n-cnt;
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_46527915/article/details/121475026