1. 程式人生 > 實用技巧 >【牛客】小白月賽30部分題目題解(自我學習用)

【牛客】小白月賽30部分題目題解(自我學習用)

https://ac.nowcoder.com/acm/contest/9667/F
知識點:貪心
我們首先要知道這題是怎麼貪心的
首先我們看得出,除了最後一個拿不到,其他的每個元素都會拿到,也就是說價值都是會加到的
而我們貪心的方法就是每次都找最大的石頭堆,然後讓他和隔壁的合併,所以最後最大的石頭堆會用到n-1次

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n; cin>>n;
    long long ans=0,m=0,x;
    for(int i=0;i<n;i++){
        cin>>x;
        m=max(x,m);
        ans+=x;
    }
    cout<<ans+m*(n-2);
    return 0;
}

——————————————————————————————————————————————————————————————————————————————————————

https://ac.nowcoder.com/acm/contest/9667/H
知識點:優先佇列
這其實是一個利用優先佇列維護陣列的一個題目,
注意到題目只有兩個操作,加數字和輸出第k小的數字,並沒有刪除數字,因此我們只需要知道每次加入數字後第k小的數字是多少就行
用優先佇列

#include <bits/stdc++.h>
using namespace std;
priority_queue<int>que;
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n,m,k; cin>>n>>m>>k;
    for(int i=0,x;i<n;i++){
        cin>>x; que.push(x);
        if(que.size()>k)que.pop();
    }
    while(m--){
        int x,y; cin>>x;
        if(x==1){
            cin>>y; que.push(y);
            if(que.size()>k)que.pop();
        }else{
            if(k>que.size())cout<<"-1\n";
            else {
                cout<<que.top()<<endl;
            }
        }
    }
    return 0;
}

————————————————————————————————————————————————————————————————————————————————————————

https://ac.nowcoder.com/acm/contest/9667/I
知識點:位運算
這裡有一個知識點在,abb=a,就是這個
所以我們根據這個可以用字首和預處理區間的異或和
可以直接再用一個數組來記錄答案

#include <bits/stdc++.h>
using namespace std;
const int N=3030;
int a[N],b[N],c[N];
int main(){
    int n,m; cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)b[i]=b[i-1]^a[i];//字首和
    for(int i=1;i<=n;i++){//長度為j的子序列最大異或和為c[j]
        for(int j=1;i+j-1<=n;j++){
            int x=b[i+j-1]^b[i-1];
            c[j]=max(c[j],x);
        }
    }
    for(int i=1;i<=n;i++)c[i]=max(c[i],c[i-1]);
    while(m--){
        int x; cin>>x;
        int ans=lower_bound(c+1,c+1+n,x)-c;//ans表示滿足的最短的長度
        if(ans>=n+1)cout<<"-1\n";//越界
        else cout<<ans<<endl;
    }
    return 0;
}

————————————————————————————————————————————————————————————————————————————————————————————

https://ac.nowcoder.com/acm/contest/9667/J
知識點:動態規劃
我是萬萬沒想到這個用dp寫這麼簡單,畢竟我想了半天貪心
不過貪心就是一種特殊的dp
不過程式碼還是比較好理解的,直接看註釋就行

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N],dp[N];
int main(){
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        dp[a[i]]++;
    }
    dp[0]=0;
    for(int i=1;i<=N;i++){
        dp[i]*=i;//將當前dp值轉換為分數
        dp[i]=max(dp[i-1],dp[i-2]+dp[i]);//看取自己還是隔壁倆
    }
    cout<<dp[N-1];
    return 0;
}