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

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

A 造数

题目描述

给定一个整数 𝑛,你可以进行以下三种操作
操作1: +1
操作2; +2
操作3: ×2
问最少需要多少次操作可以将 0转为为 𝑛。n(0≤n≤10^9)。

思路

最少操作,就要考虑乘2,所以判断n为奇数,-1,偶数 , / 2。依次循环,就能得到答案。

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
signed main()
{
	 	int n,ans=0;
			cin>>n;
			if(n==1) cout<<"1";
			else if(n==0) cout<<"0";
			else
			{
				while(n!=1)
				 	{
				 		ans++;
					 	if(n%2!=0)
						 	n--;
					 	else
					 	n/=2;
					 }
					  cout<<ans;
			}
 
}

D 小蓝的二进制询问

题目描述

小蓝有 t 组询问,每次给定两个数字 𝑙,𝑟。你需要计算出区间 [𝑙,𝑟] 中所有整数在二进制下1的个数之和。由于结果特别大,你只需要计算出结果模998244353之后的值即可。
(1≤t≤10 ^5 ) (1≤l≤r≤10 18)

思路

由于二进制只有0,1。所以,可以考虑从数字0开始,各个数位上0,1,是如何变化的。 从右往左数,第一位是01010101,两个为一周期,每个周期出现一次1。第二位是001100110011,四个数为一周期,每个周期出现两次1。依次类推,第n个数位,周期是2 ^ n , 每个周期出现2^(n-1)个1 。所以答案就是 C[0,r]-C[0,L-1]

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int calculator(int l)
{
   int sum=0,ll=2;//第一个数位周期是2
   l+=1;// 周期从0开始,L是第L+1个数
   while(ll<l*2) //  周期的后半部分会出现1,所以 l >ll /2
   {
    sum+=l/ll*ll/2;  //每ll个一循环,有ll/2个1.
    if(l%ll-ll/2>0)  //加上不足一周期的
    sum+=l%ll-ll/2;
    sum%=mod;
    ll*=2; 
   }
	if(l==1) return 0;
   return sum%mod;
}
void solve()
{
   int l,r;
   cin>>l>>r;
   l=calculator(l-1);
   r=calculator(r);
   cout<<(r-l+mod)%mod<<endl;
}
signed main()
{
   int t;
   cin>>t;
   while(t--)
   solve();
}

F 两难抉择新编

题目

在这里插入图片描述

思路

这里涉及到 异或的自反性,先算出所有数的异或和,再暴力枚举比较大小。

自反性: a ^ b ^ b =a
交换律:a^ b = b^ a
结合律:(a^ b) ^ c = a ^ ( b ^ c)

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005];
signed main()
{
    int n,ans=0,ma=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    { cin>>a[i];
     ans=ans^a[i];
     }
	 for(int j=1;j<=n;j++)//i,j,由于循环字母写错了,导致结果不对
    {
        for(int i=1;i<=n/j;i++)
        { int t=a[j]+i;
          ma=max(ma,ans^a[j]^t);//起初没定义ma,直接用的ans,值在变,致使结果出错
		    t=a[j]*i;
		  ma=max(ma,ans^a[j]^t);
        }
     }  
    cout<<ma;
    return 0;
}

G 旅途的终点

题目

在这里插入图片描述

思路

用到了反悔贪心,复杂的问题就简单化了,不需要考虑太多杂七杂八的啦。定义个小顶堆,每到一个数就存进去,先假设全用的 k,用完就考虑弹出最小值,用m。当>=m,就break。(联想到了鸡兔同笼,假设全是鸡…或者假设鸡和兔都抬起两只脚…)

代码
 #include<bits/stdc++.h>
 using namespace std;
 #define int long long
 int a[200005],kk[200005];
 signed main()
 {
     int n,m,k,ans=0,i;
     cin>>n>>m>>k;
     for(i=1;i<=n;i++)
    cin>>a[i];
     priority_queue<int,vector<int>,greater<int>> q;
    for( i=1;i<=n;i++)
    {
	  q.push(a[i]);
	  if(q.size()>k)
	  {
	   	 
	   	ans+=q.top(),q.pop();
	   	if(ans>=m) break;
	  }
	}
	cout<<i-1;
     return 0;
 }

H 两难抉择

题目

在这里插入图片描述

思路

找到最大的数,再乘或者加最大的。我还考虑了当最大的为1或者n==1时,选择+n。这完全是多此一举,直接代码比较大小就行了。可以交给计算机的,不需要自己思考判断。

代码
 #include<bits/stdc++.h>
 using namespace std;
 #define int long long
 #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
 int a[200015];
 signed main()
 {
 	   IOS
       int n,sum=0,ma=0;
    	cin>>n;
    	for(int i=1;i<=n;i++)
    	{
  	  	cin>>a[i];
  	  	ma=max(ma,a[i]);
  	  }
    	for(int i=1;i<=n;i++)
  	  	sum+=a[i];
  	  	if(ma==1||n==1)
  	      cout<<sum+n;
  	    else
  	    cout<<sum+ma*(n-1);
 }
 

I 除法移位

题目

在这里插入图片描述

思路

在能力范围内,将最大的放到最前面就ok了。我又搞复杂了,直接保证,在n和t 范围内,找到最大的就好了,一个循环就行。而我和上一题一样又在自己考虑什么时候选哪个,t==0时,最大的为a[1]时,t<n时,没必要。原本想特判,简单考虑,但还不如整体解决,还会漏掉条件。

代码(优化后)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int a[200005];
signed main()
{
	IOS
	int n,t,ma=1,ans=0,f=0;
	cin>>n>>t;
 	for(int i=1;i<=n;i++)
 	{
	 	cin>>a[i];
	 }
	for(int i=n;i>=1&&f<t;i--)
	{
			f++;
		  if(a[i]>a[ma])
	    	ma=i,ans=f;	
	}
	cout<<ans;
}

K 图上计数(Easy)

题目

在这里插入图片描述

思路

这么多人过,也那么快,肯定很简单。而且根据题意,如果从图出发,太复杂了,所以要么0,要么顶点分两半。由于我按便涉及到的顶点算的,错了,就开始摇摆,到底是不是这个思路,耗时太长,不坚定,这时候很混乱,思考都没有逻辑性了,应该赛场上试一下用n,当然,我也觉得题目不合理,可能还是不重视这个比赛,后面走马观花,没专注于一题。

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int a[1000052];
signed main()
{
	IOS
	int n,m,u,v,h=0;
	cin>>n>>m;
 	for(int i=1;i<=m;i++)
 	{
	 	cin>>u>>v;
	 	if(a[u]==0)
	 	a[u]++,h++;
	 	if(a[v]==0)
	 	a[v]++,h++;
	 	
	 }
	 cout<<h/2*(h-h/2);
 	
}

总结

这7题都比较简单,略动脑子,简短的代码就可以Ac。难就难在,精准把握正确思路,代码编写。不然很容易搞复杂。很多次都是这种感觉,难道是眼高手低?学到了反悔贪心,异或自反性,二进制01周期。

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值