2022第十三届蓝桥杯c++c组

24 篇文章 12 订阅
8 篇文章 1 订阅

目录

纸张尺寸

求和

数位排序

选取异或

消除游戏

重新排序

只因能升级

重复的数


因为本人使用AcWing比较多,所以这里的题目链接全都在AcWing上,如果大家想更系统的去查看这些题目,大家可以前往C语言网查找原题

纸张尺寸

原题链接:4652. 纸张尺寸 - AcWing题库

很简单的一道题目,直接进行循环判断即可

代码如下:

#include<iostream>

using namespace std; 

int main()
{
	string arr;
	cin>>arr;
	int k=arr[1]-'0';
	int a=1189,b=841;
	while(k--)
	{
		swap(a,b);
		b/=2;
	}
	cout<<a<<endl<<b<<endl;
}

求和

原题链接:4644. 求和 - AcWing题库

这道题先看一眼发现数据个数在2e6,首先排除两重暴力循环,那么就要思考其他解法,发现,我们要求的是两两相乘再相加,但是对于某一个数来说,就是他和除了他本身的其他所有数相乘再相加,那么基于此,我们可以直接优化掉一重,首先求出所有数的和,接着直接循环一遍数组,用和减去ai再乘以ai,相加即可

代码如下:

#include<iostream>

using namespace std;

typedef long long LL;
int arr[200010];

int main()
{
	int n;
	cin>>n;
	LL ans=0;
	for(int i=1;i<=n;i++) 
	{
		cin>>arr[i];
		ans+=arr[i];
	}
	LL cnt=0;
	for(int i=1;i<=n;i++)
	{
		cnt+=arr[i]*(ans-arr[i]);
		ans-=arr[i];
	}
	cout<<cnt<<endl;
 } 

数位排序

原题链接:4653. 数位排序 - AcWing题库

在各个数位和相同的情况下,我们需要选出最小的数,让他排在最前面,所以这道题目的思路就清晰了,我们直接开个结构体存一下数字和他的各数位和,然后进行结构体排序即可;

很简单的结构体排序题目,1e6很轻松就可以过掉,sort可以快速排完;

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

struct ST
{
	int in,he;//数,总和,位数 
}arr[1000010];

void pd(int p)
{
	int k=p;
	int a=0;
	while(k!=0)
	{
		a+=k%10;
		k/=10;
	}
	arr[p].he=a;
}

int cmp(ST a,ST b)
{
	if(a.he!=b.he)
	return a.he<b.he;
	return a.in<b.in;
}

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) 
	{
		arr[i].in=i;
		pd(i);
	}
	sort(arr+1,arr+1+n,cmp);
//	for(int i=1;i<=n;i++) 
//	cout<<arr[i].he<<' ';
	cout<<arr[m].in<<endl;
}

选取异或

原题链接:4654. 消除游戏 - AcWing题库

首先,肯定不能直接暴力,暴力绝对会超时,那么我们就要想其他办法,我们很容易想到,直接遍历原来的数组,我们直接查找谁和他异或,加入到他里面就行,但是这样也有一个问题,循环次数还是n方,而且接下来查询虽然快,但第二步遍历查找很容易被卡死,这个我没试过,大家可以试一试;

第三个方法是,我们在这个数对应的异或数中加入这个数的坐标,这样我们就把位置的判断转换成了数的判断,而且这样写的话第一步是n的复杂度;

于是我们就可以写下这个代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
int n,m,l,r,k;
int a[100010];
set<int> s[2000003];

int main()
{
	ios_base::sync_with_stdio(0);
    cin.tie(0);
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s[a[i]^k].insert(i);//把与这个位置的数异或的结果加上这个位置 
	}
	for(int i=1;i<=m;i++)
	{
		cin>>l>>r;
		int flag=0;
		for(int j=l;j<=r&&flag==0;j++)//从l到r之间进行循环 
		{
			int A=a[j];
			if(s[A].size()==0) continue;//如果s这个位置为空,说明没有任何一个数异或得到这个数,可以直接退出 
			for(set<int>::iterator it=s[A].begin();it!=s[A].end();it++)
                {
                    if(l<=*it&&*it<=r)//如果找到这个数他的异或结果有位置在l到r之间,直接退出 
                    {
                        flag=1;
                        break;
                    }
                    else if(*it>r)    break;//优化,大于r说明已经找不到了,直接退出 
                }
		}
		if(flag==0) cout<<"no"<<endl;
		else cout<<"yes"<<endl;
	}
}

消除游戏

本来以为这是一道很简单的题目,想着直接开个栈存一下进行判断就行,后来才发现,人家要每一次删一遍,删完再删,如果用栈的话他会一直删,于是就放弃了栈的想法,使用了暴力模拟,但是暴力模拟也有数据过不掉,我这里实在是没招了,期待大家的更好的代码:

#include<iostream>

using namespace std;

int main()
{
	string a,b;
	cin>>a;
	while(1)
	{
		int flag=0;//flag的含义是,如果遇到两种情况,他们后面的字符是都不加进去的,我们要特判消除 
		for(int i=0;i<a.size();i++)
		{
			if(flag)
			    flag--;
			if(a[i]!=a[i+1]&&a[i+1]==a[i+2]&&i+2<a.size())//第一种情况,前不等后等,那个会有两个字符不加进去 
			{
				flag=2;
				continue;
			}
			else if(a[i]==a[i+1]&&a[i+1]!=a[i+2]&&i+2<a.size())//前等后不等,会有三个加不进去,这时候可能存在加入的情况 
			{
				if(!flag)//特判这步加入的情况 
					b+=a[i];
				flag=3;
				continue;
			}
			if(!flag)//如果没被标记,就加入 
				b+=a[i];
			
		}
		if(b.size()==a.size()) break;//出现没有消除的情况,说明已经消除完成 
		else if(b.size()==0)//发现为空了,直接退出 
		{
			cout<<"EMPTY";
			break;
		}
		a=b;
		b="";
	}
	if(b.size()) cout<<a<<endl;
 } 

重新排序

原题链接:4655. 重新排序 - AcWing题库

这道题目有两种做法,第一种是,因为我们只需要管谁出现次数多,谁出现次数少,所以可以直接进行排序,把每个数的出现次数进行排序,然后把原数排序,然后直接进行对应相乘,加起来减去原来的结果即可,但是这样做有一个问题,这个数的大小是超LL的,我们只能先减去再进行乘法;

于是我们可以在排序出现次数时,把原数组位置随之改变,这样再开一个数组进行排序,每一次相乘使用一个差值相乘,这样就可以避免超出LL;

代码如下:

#include<iostream>
#include<algorithm> 
using namespace std;

typedef long long LL;
int n,m;
int ae[100010];
struct ST
{
	int a;
	int b;
}arr[100010];

int cmp(ST x,ST y)
{
	return x.b<y.b;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&arr[i].a);
		ae[i]=arr[i].a;//额外存储; 
	}
	cin>>m;
	while(m--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		arr[x].b++,arr[y+1].b--;//使用前缀和优化 
	}
	for(int i=2;i<=n;i++) arr[i].b+=arr[i-1].b;
	
	sort(ae+1,ae+1+n);
	sort(arr+1,arr+1+n,cmp);//自定义排序 
	
//	for(int i=1;i<=n;i++)
//		cout<<ae[i]<<' '<<arr[i].a<<' '<<arr[i].b<<endl;
		
	LL cnt=0;
	for(int i=n;i>=1;i--) cnt+=(LL)(ae[i]-arr[i].a)*arr[i].b;//使用差值可以避免超出LL 
	
	cout<<cnt<<endl;
}

只因能升级

首先就发现m太大了,我们要向计算技能,一种方法就是把所有技能加点情况全列出来,然后进行排序,取前m个即可,但是m在int尽头是肯定的存不下的,而且排序也会超时;

这里有个很经典转换,我们发现技能加点在1e6之间,我们能不能想办法,把每个技能加点都存在数据范围中,这样就可以存下所有情况,只需要遍历1e6,把m减完即可;

但是这样有个问题,会超时,1e5的数据大小为1e6,差值为1就是1e11,肯定超时,所以这个解法看看就行了,暴力骗点分。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;

LL arr[1000010];
 
int main()
{
	LL n,m;
	cin>>n>>m;
	while(n--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		while(a>0)
		{
			arr[a]++;//如果a出现了一次,就说明可以加点一次 
			a-=b;
		}
	}
//	for(int i=1;i<=10;i++) cout<<i<<' '<<arr[i]<<endl;
	LL ans=0;
	for(int i=1000000;i>=1;i--)//只需要遍历所有加技能点的情况即可 
	{
		if(arr[i]&&m>=arr[i]) 
		{
			ans+=(LL)arr[i]*i;
			m-=arr[i];
		}
		else if(arr[i]&&m<arr[i])//判断m不够加点的情况 
		{
			ans+=(LL)m*i;
			m=0;
		}
		if(m==0)
		break;
	}
	cout<<ans<<endl;
}

重复的数

看着答案说是离线莫队,我也不会,这算是算法进阶的难度,大家有兴趣可以自己去学;

暴力写法也比较简单,这里就不展示代码了

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 第十三届蓝桥杯研究生C是中国计算机教育著名的比赛之一,全称为“全国计算机等级考试蓝桥杯全国软件和信息技术专业人才大赛研究生C赛题”。此次比赛的赛题主要面向软件开发这一领域,涵盖了多种技术方向,包括Java、C++、Python、机器学习、分布式计算、区块链等等。 此次比赛旨在鼓励研究生参与实际项目开发,培养学生解决实际问题的能力和实践经验,同时也为企业提供一批高水平的技术人才。比赛内容难度较高,需要参赛者具备较高的技术水平和实际开发经验。 同样,第十三届蓝桥杯研究生C也是一次充满挑战和机遇的比赛,参赛者需要克服技术难题,理解业务需求,开发出高质量的软件产品,同时还需要注意代码规范,注重代码可读性和可维护性。通过本次比赛,研究生们不仅能够提高自己的技术能力和实践经验,还能够结交同行业的优秀人才,扩展自己的人脉和职业发展空间。 总之,第十三届蓝桥杯研究生C是一次充满挑战和机遇的比赛,期待更多的研究生参与其中,展现自己的才华和实力,为中国软件开发行业的发展做出贡献。 ### 回答2: 第十三届蓝桥杯研究生C题是一道关于动态规划算法的题目,题目难度较大,需要研究生具备扎实的算法基础和编程基础。 这道题目要求我们设计一个程序,计算从一个正方形棋盘左上角到右下角的所有路径中,经过任意1个格子的路径的总数。具体来说,我们需要使用动态规划的思想,利用空间换时间的策略,在棋盘上填表,记录每个格子前面路径中经过的格子数量,使得遍历表格时能够快速计算各个格子之间的相关关系,从而求得最终结果。 本题的难点在于需要设计出时间复杂度为O(n^2)的算法,需要学生具备较高的算法设计和分析能力。同时,由于本题考察的是研究生学生的素质,除了算法的正确性,良好的代码风格和工程能力也是评价标准之一。因此,在解题过程中,应当注意代码的规范性和可读性,编写注释,并遵循良好的编码规范,以展示出研究生的优秀素质。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值