河南萌新联赛2024第(一)场:河南农业大学(ADFGHIK)

题目链接:https://ac.nowcoder.com/acm/contest/86639

写在前面

这是我打的第一次萌新联赛,总体来说题目不算太难,但以我现在的水平只能写出中等偏下的题目,还是得先打好基础,在往上拔高

回归正题

按题目的难度系数,分为A,H,K,I,F,G,D
本文按难度系数从上往下

A-造数

思路

签到题,我们将操作倒过来从n到0经过几个步骤即可

编程

void solve(){
	int n;cin >> n;
	int cnt=0;
	if(n==0){
		cout << 0 ;
		return ;
	}
	if(n==1||n==2){
		cout << 1 ;
		return ;
	}
	while(n/2>0){
		if(n%2){
			n--;
			cnt++;
		}
		n/=2;
		cnt++;
	}
	cout << cnt << endl;
	return ;
}

H-两难抉择

思路

签到题,找出序列中最大的数,然后让他乘以n即可,考虑特判当全是1的时候让其中一个1加上n才是最优

编程

void solve(){
	int n;cin >> n;
	int maxn=0;
	int sum=0;
	for(int i=1;i<=n;++i){
		cin >> a[i];
		sum+=a[i];
		maxn=max(maxn,a[i]);
	} 
	if(maxn==1){
		cout << sum+n ;
	}
	else{
		cout << sum-maxn+maxn*n;
	}
	return ;
}

K- 图上计数(Easy)

思路

简单的思维题,由于它可以删无数条边,那么我们只需要将所有边拆散然后均分为2堆连通块即可

编程

void solve(){
	int n,m;
	cin >> n >> m;
	for(int i=1;i<=m;++i){
		int u,v;
		cin >> u >> v;
	}
	cout << (n/2)*(n-n/2) ;
	return ;
}

I- 除法移位

思路

由于只有一个被除数,其他全是除数,因此我们优先考虑数列中最大的数做被除数,同时我们还要考虑最大的数位移的次数要小于等于t,否则就取次大的数,直到找到满足位移次数小于等于t的数即可

编程

bool cmp(PII x,PII y){
	return x.fi>=y.fi;
}
void solve(){
	int n,t;
	vector<PII> b;
	cin >> n >> t;
	b.resize(n);
	for(int i=0;i<n;++i){
		cin >> a[i];
		b[i]={a[i],i}; 
	} 
	sort(b.begin(),b.end(),cmp);
	for(int i=0;i<n;++i){
		if(b[i].se==0){
			cout << 0 ;
			return ;
		}
		if(n-b[i].se<=t){
			cout << n-b[i].se;
			return ;
		}
	}
	return ;
}

F- 两难抉择新编

思路

考点:暴力模拟,先将数列里所有数都进行异或处理,然后暴力模拟1到n/i的所有数即可,最后比较操作1和操作2大小,输出最大值即可

编程

void solve(){
	int n;cin >> n;
	int sum=0;
	for(int i=1;i<=n;++i){
		cin >> a[i];
		sum^=a[i];
	}
	int maxn=0;
	for(int i=1;i<=n;++i){
		 for(int j=1;j<=n/i;++j){
		 	int x=a[i];
		    int y=a[i];
		 	x=x+j,y=y*j;
		 	int k=sum,l=sum;
		    k^=a[i],l^=a[i];
		    k^=x;maxn=max(maxn,k);
		    l^=y;maxn=max(maxn,l);
		 }	 
	}
	cout << maxn ;
	return ; 
}

G-旅途的终点

思路

考点:反悔贪心,我们先开一个最大堆存储每次经过的路径,我们先不考虑释放神力k,每次经过国家都消耗生命值,当生命值小于等于0时,考虑反悔之前消耗生命值最多的一次,然后将栈顶出栈,若k次数用尽,则输出当前坐标减去1(不包含当前坐标),若最后全部通过则输出n

编程

void solve(){
	int n,m,k;
	cin >> n >> m >> k;
	priority_queue<int> q;
	for(int i=1;i<=n;++i){
		cin >> a[i];
	} 
	for(int i=1;i<=n;++i){
		q.push(a[i]);
		m-=a[i];
		while(m<=0){
			if(k<=0){
				cout << i-1 << endl;
				return ;
			}
			k--;
			m+=q.top();
			q.pop();
		}
	}
	cout << n << endl;
	return ;
}

D-小蓝的二进制询问

思路

在这里插入图片描述

考虑每一位二进制位的贡献。算出1到R的贡献减去1到L-1的贡献,就是L到R的贡献
从低位往高位枚举x的二进制位,简单枚举一下1到15的二进制可以发现,第0位是每2次出现一个1,第1位是每4次出现2个1,第2位是每8次出现4个1,可以看出,对于每一位,画红框的地方是每一位的循环节,第 k 位的循环节长度为2k+1,其中有2k个1,所以我们可以按位枚举,计算每一位上总共有多少个循环节和剩下非循环节中 1 的个数,因为这里是从 0 开始计算每一行的长度,所以实际计算时 x 需要加 1

编程

int mod=998244353;
int f(int x){
	int ans=0,a=2;
	x++;
	while(x>=a/2){
		ans=(ans+(x/a)*(a/2))%mod;//循环节里面1的个数
		if(x%a!=0) ans=(ans+max(0ll,x%a-(a/2)))%mod;//非循环节1的个数
		a*=2;
	}
	return ans;
}
void solve(){
	int l,r;
	cin >> l >> r;
	cout << (f(r)-f(l-1)+mod)%mod << endl;
	return ;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值