【牛客】小白月赛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;
}