文章目录
河南萌新联赛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周期。