牛客小白月赛40

牛客小白月赛

A

这一题其实直接暴力就可以了。推荐一个函数:

__builtin_popcount(x) //返回x在二进制表示1的个数
__builtin_clz (unsigned int x) //返回前导的0的个数。

代码:

#include <bits/stdc++.h>
using namespace std;
int main() {
  int T;
  scanf("%d",&T);
  while (T--) {
    int x, ans = 0;
    scanf("%d",&x);
    while (x) {
      if (__builtin_popcount(x) & 1)
        x ^= 1;
      else {
        int bit = 31 - __builtin_clz(x);
        x ^= 1 << bit;
      }
      ans++;
    }
    printf("%d\n", ans);
  }
  return 0;
}

D

签到题,判断有多少个两两相同连在一起的字符就行了。

代码:

#include<bits/stdc++.h>
using namespace std;
ll n,m,k;

void solve(){
	string s;
	cin>>s;
	int n=s.size();
    int tt=n;
	for(int i=0;i<tt-1;i++){
		if(s[i]==s[i+1]) n++;
	} 	
	cout<<n<<endl;
} 

int main(){	
	int T=1;
    cin>>T;
	while(T--) solve();
}

E

二分答案,二分最多的小组的人数

那么check函数,数据范围挺小的,直接可以桶 计数。判断最多可以分成多少组,组数是不是小于 m就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
int a[1000010],t[1000010];
int n,m;
bool chk(int mid){
    if(mid==0) return true;//其实根本不会有这种情况
    int ans=0,mx=0;
    for(int i=1;i<=100000;i++){
        if(t[i]){
            ans=ans+(t[i]+mid-1)/mid;
        }
    }
    return ans<=m;//判断能不能分那么多组
}

int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>a[i];
        t[a[i]]++;
    }
    int l=0,r=n;
    int ans=100000;
    while(l<=r){
        int mid=(l+r)/2;
        if(chk(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    if(ans==100000) cout<<-1<<endl;
    else cout<<ans<<endl;
}

F

题意

有n个 方块,每一个方块都一个数aia_{i} ,为正数可以往前跳,跳到 iii+a[i]i+a[i],负数可以往回跳 可以跳到11i+a[i]i+a[i]

思路

这个题目有很明显的转移,且数据范围较小,可以采用动态规划。 假设 dp[i]dp[i] 表示到达第 i 个方块的最短用时。由于负数相当于往回走,用时肯定更长,负数肯定可以直接跳过,有负数可能导致不能遍历到第 n 个 方块,如果可以遍历到第 n 个方块直接输出 dp[n]dp[n] ,如果不能输出 -1 ;

  • 转移方程:
dp[i+a[i]]=min(dp[i]+1,dp[i+a[i]);

负数直接跳过

  • code
#include<bits/stdc++.h>
using namespace std;
int dp[30000],a[20000];

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],dp[i]=INT_MAX;
    dp[1]=0;
    for(int i=1;i<=n;i++){
        if(a[i]>0){
            for(int j=i+1;j<=i+a[i];j++){
                dp[j]=min(dp[i]+1,dp[j]);
            }
        }
    }
    if(dp[n]==INT_MAX) cout<<-1<<endl;
    else cout<<dp[n]<<endl;
}

G

差分、前缀和

枚举每一个K,去一个最大值

#include<bits/stdc++.h>
using namespace std;
int a[1000010];
int sum[6000010]={0};

int main(){
    int n,m,p;
    cin>>n>>p;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++){
        sum[a[i]-p+1000000]++;
        sum[a[i]+p+1000000+1]--;
    }
    int ans=0;
    for(int i=0;i<=2000000;i++){
        sum[i]+=sum[i-1];
        ans=max(sum[i],ans);
    }
    cout<<ans<<endl;
}

H

要使得选的数的gcd等于x,那么选的数一定是 x的倍数,所以我们枚举 x,2x,3x,4x,如果在数组中出现过,我们就对他 取一个gcd,如果最后这些数的gcd等于 x,那么输出YES,否则输出NO

时间卡的有点紧,用快一点的输入输出

代码:

#include<bits/stdc++.h>
using namespace std;

int n,a[1000010],m,h[1000010];
void solve(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++) h[i]=0;//注意不要用memset,会超时
    for(int i=1;i<=n;i++)  scanf("%d",&a[i]),h[a[i]]++;
    int x;
    while(m--){
        scanf("%d",&x);
        bool ok=true;
        int p=x,tt=0;
        for(int i=x;i<=n&&tt!=x;i+=x){
            if(h[i]) tt=__gcd(i,tt);
        }
        if(tt==x) printf("YES\n");
        else printf("NO\n");
    }
}

int main(){
    int t;
    cin>>t;
    while(t--) solve();
}

I

范围只有到10,直接STL,全排列函数,next_permutation(a.begin(),a.end()),返回下一个比他大的全排列。判断每一个排列是否符合条件。

DFS搜全排列也是一样的。

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define endl '\n'
typedef long long ll;
const int N=5e5+10;
const int M=1e6+7;
const int mod=1e9+7;
ll n,m,k;

ll a[N],b[N];

void solve(){
	cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) b[i]=i+1;
    int ans=0;
    do{
    	bool ok=true;
        for(int i=0;i<n;i++){
            int pos=0;
            if(a[i]==i+1) continue;
            for(int j=0;j<n;j++){//找到他的位置,
                if(b[j]==i+1) {
                    pos=j+1;
                    break;
                }
            }
            for(int j=0;j<pos;j++){//判断是不是在他的前面
                if(b[j]==a[i]){
                    ok=false;
                    break;
                }
            }            
        }
        if(ok) ans++;
    }while(next_permutation(b, b+n));
    cout<<ans<<endl;
} 

int main(){	
	solve();
}
全部评论

相关推荐

点赞 评论 收藏
分享
最近群里有很多同学找我看简历,问问题,主要就是集中在明年三月份的暑期,我暑期还能进大厂嘛?我接下来该怎么做?对于我来说,我对于双非找实习的一个暴论就是title永远大于业务,你在大厂随随便便做点慢SQL治理加个索引,可能就能影响几千人,在小厂你从零到一搭建的系统可能只有几十个人在使用,量级是不一样的。对双非来说,最难的就是约面,怎么才能被大厂约面试?首先这需要一点运气,另外你也需要好的实习带给你的背书。有很多双非的同学在一些外包小厂待了四五个月,这样的产出有什么用呢?工厂的可视化大屏业务很广泛?产出无疑是重要的,但是得当你的实习公司到了一定的档次之后,比如你想走后端,那么中厂后端和大厂测开的选择,你可以选择中厂后端(注意,这里的中厂也得是一些人都知道的,比如哈啰,得物,b站之类,不是说人数超过500就叫中厂),只有这个时候你再去好好关注你的产出,要不就无脑大厂就完了。很多双非同学的误区就在这里,找到一份实习之后,就认为自己达到了阶段性的任务,根本不再投递简历,也不再提升自己,玩了几个月之后,美其名曰沉淀产出,真正的好产出能有多少呢?而实际上双非同学的第一份实习大部分都是工厂外包和政府外包!根本无产出可写😡😡😡!到了最后才发现晚了,所以对双非同学来说,不要放过任何一个从小到中,从中到大的机会,你得先有好的平台与title之后再考虑你的产出!因为那样你才将将能过了HR初筛!我认识一个双非同学,从浪潮到海康,每一段都呆不久,因为他在不断的投递和提升自己,最后去了美团,这才是双非应该做的,而我相信大部分的双非同学,在找到浪潮的那一刻就再也不会看八股,写算法,也不会打开ssob了,这才是你跟别人的差距。
迷茫的大四🐶:我也这样认为,title永远第一,只有名气大,才有人愿意了解你的简历
双非本科求职如何逆袭
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务