2020年牛客算法入門課練習賽1題解

題目鏈接

A.第k小數

題意:
nk給一個長度爲n的數列,找出第k小數
題解:
本來是一個簽到題,結果數據範圍給出了
wa大批的wa就出現了
n<=5e6sortak最後n<=5e6,直接快讀加sort找a_k就行

AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=4e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    
    int _;
    while(cin>>_){
        while(_--){
            int n,k;
            cin>>n>>k;
            for(int i=1;i<=n;i++)cin>>a[i];
            sort(a+1,a+1+n);
            cout<<a[k]<<endl;
        }
    }
    return 0;
}


B.不平行的直線

題意:
n有n個不重複點,任意兩個點可以組成線段
能找出最多多少條線段不互相平行或重合
題解:
由於幾條線平行只能選一條
所以直接看每條線的斜率
如果重複出現,那麼後面的就不能被繼續選中

set最直接的方法,set存斜率,判一下斜率不存在的情況是否出現
1set.size()如果出現,不管幾次都加1,然後看set.size()

doubleset但是斜率會出現小數,需要用double,set可能會被卡精度(這道題沒有)
所以可以取出所有斜率,排序一下,自己手動判重
xy<eps手動用x-y<eps判相等不會出現被卡精度的情況

AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
 
double x[210],y[210];

 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>x[i]>>y[i];
    set<double> s;
    int f=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            if(!(y[i]-y[j])){f=1;continue;}
            s.insert((x[i]-x[j])/(y[i]-y[j]));
        }
    cout<<s.size()+f;
    return 0;
}

C. 丟手絹

題意:
nn個小朋友圍成一個圈,給出相鄰兩個小朋友的距離
最後問任意兩個小朋友的最遠距離
題解:
直接操作可以是枚舉任意兩個小朋友,看他倆的距離
但是這樣會超時
從一個朋友的左邊出發到右邊,每個小朋友和他的距離一定是個凸函數
所以可以考慮三分,對每個小朋友進行三分找最遠距離
通過前綴和維護任意兩個小朋友直接的距離
環的距離有兩個方向,所以要記得兩個方向取距離
AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

ll i,a[maxn];
ll s[maxn],sum;
ll check(ll x){
    ll y=s[x]-s[i-1];
    return min(y,sum-y);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;cin>>n;
    for(i=1;i<=n;i++)
        cin>>a[i],sum+=a[i];
    for(i=1;i<=2*n;i++){
        if(i<=n)s[i]=s[i-1]+a[i];
        else s[i]=s[i-1]+a[i-n];
    }
    ll ans=0;
    for(i=1;i<=n;i++){
        ll l=i,r=i+n;
        while(l+10<r){
            ll lm=l+(r-l)/3,rm=r-(r-l)/3;
            if(check(lm)>=check(rm))r=rm;
            else l=lm;
        }
        for(ll j=l;j<=r;j++)
            ans=max(ans,check(j));
    }
    cout<<ans;
    return 0;
}


D. 二分

題意:
猜數遊戲,你猜一個數,裁判告訴你答案比這個數大還是小或等於
但是裁判會忘記了自己說的
n所以裁判說的不一定正確,告訴你n條裁判說的
判斷裁判說的是正確的可能有幾句
題解:
這個總容易想到的就是枚舉這個數
int但是這個數太大,是在int範圍內的所有數
所以可能會想到三分,但是通過自己寫幾個數據實驗一下
發現並不是一個凸函數
所以我們就考慮用差分來做,去計數每一條正確的區間
由於數較大,所以要進行離散,將給出的數和左右相鄰的數一起離散
如果答案大於某個數,把這個數對於的離散後的位置右邊用差分加一
相等就是這個點加一,小於的話同理大於的情況
最後統計每個數的正確情況,找到最大的
AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
 
int n;
ll x[maxn],a[maxn],c[maxn];
char y[maxn];
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n;
    int len=0;
    for(int i=1;i<=n;i++){
        cin>>x[i]>>y[i];
        c[++len]=x[i];
        c[++len]=x[i]-1;
        c[++len]=x[i]+1;
    }
    sort(c+1,c+1+len);
    len=unique(c+1,c+1+len)-c-1;
    for(int i=1;i<=n;i++){
        int p=lower_bound(c+1,c+1+len,x[i])-c;
        if(y[i]=='.')a[p]++,a[p+1]--;
        if(y[i]=='-')a[p+1]++,a[len+10]--;
        if(y[i]=='+')a[1]++,a[p]--;
    }
    ll ans=0;
    for(int i=1;i<=len+10;i++)
        a[i]+=a[i-1],ans=max(ans,a[i]);
    cout<<ans;
    return 0;
}

E. 交換

題意:
n使有n個無序的數,通過最少多少次交換可以使他有序
題解:
n交換數,最差情況是n次,把每個數交換到對應的位置
但是如果出現如下情況
142356比如數列1,4,2,3,5,6
432244332這裏的4,3,2。2的位置放着4,4的位置放着3,3的位置放着2
2434這樣稱爲一個循環節,只要2和4換,3和4換就可以了
xx1循環節有x個數,只要換x-1個數就可以讓所有數都歸位
所以就是,有幾個循環節就可以少換幾次
nn總共是n次,那麼最後結果就是用n-循環節數
然後需要找循環節
由於數是不連續的,先對數排序,找出每個數應該在的位置
然後對未訪問的數,找對應這個位置應該放的數在哪
直到再次找到這個循環節的頭爲止
AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
 
bool flag[maxn];
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;cin>>n;
    vector<int> v;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        v.pb(x);
    }
    map<int,int> m;
    vector<int> v1=v;
    sort(all(v1));
    for(int i=0;i<n;i++)m[v1[i]]=i;
    int ans=0;
    for(int i=0;i<n;i++){
        if(!flag[i]){
            int j=i;
            while(!flag[j]){
                flag[j]=1;
                j=m[v[j]];
            }
            ans++;
        }
    }
    cout<<n-ans;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章