蓝桥杯第七届C/C++ B组

1
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),

如果一共有100层,共有多少个煤球?

请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

思路

简单题,不说了

题解

#include<iostream>
using namespace std;

int main(){
	int dp[1000];
	dp[1] = 1;
	dp[2] = 3;
	int sum = 4;
	for(int i = 3;i<=100;i++){
		dp[i] = dp[i-1] + i;
		sum+=dp[i];
	}
	cout <<sum<<endl;
} 

2
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

现在算起来,他一共吹熄了236根蜡烛。

请问,他从多少岁开始过生日party的?

请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

思路

太简单了,不说了
#include<iostream>
using namespace std;
int sum;
int main(){
	for(int i = 1;i<=100;i++){
		for(int j = i;j<=100;j++){
			sum += j;
			if(sum == 236){
				cout <<i<<endl;
				break;
			}
		}
		sum = 0;
	}
} 

3
B DEF
A + — + ------- = 10
C GHI

(如果显示有问题,可以参见【图1.jpg】)

这个算式中AI代表19的数字,不同的字母代表不同的数字。

比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。

这个算式一共有多少种解法?

注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

思路

注意选double 全排列即可

题解

#include<iostream>
using namespace std;
int sum,ans;
int b[100];
double a[100]; 
void dfs(int x){
	if(x == 9){
		if(a[0] + a[1]/a[2] + (a[3]*100+a[4]*10+a[5])/(a[6]*100+a[7]*10+a[8]) == 10.0){
			ans++;
		}
		return;
	}
	for(int i = 1;i<10;i++){
		if(!b[i]){
			a[x] = i;
			b[i] = 1;
			dfs(x+1);
			b[i] = 0;
		} 
	}
}
int main(){
	dfs(0);
	cout<<ans<<endl;
} 

4
快速排序

思路

简单说就是拿一个数开始比,小的放左边,大的放右边

题解

4.5 由于蓝桥杯取消了填空,就不做了

6
如下的10个格子
±-±-±-+
| | | |
±-±-±-±-+
| | | | |
±-±-±-±-+
| | | |
±-±-±-+

(如果显示有问题,也可以参看【图1.jpg】)

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

此题还是回溯,从第一个格子开始填,并用vis数组记录一个结果中填的数是否被用过
dfs前进行判断,判断四个方向是否可以填

题解

#include<iostream>
using namespace std;
int mp[5][5];
int cnt;
bool vis[10];
int abs(int x){
	return x>0?x:-x; 
}
bool check(int x,int y,int v){
	if(x > 0){
		if(abs(mp[x-1][y] - v) == 1)
			return false;
		if(y > 0 && abs(mp[x-1][y-1] - v) ==1)
			return false;
		if(y < 3 && abs(mp[x-1][y+1] - v) == 1)
			return false;
	}
	if(y > 0 && abs(mp[x][y-1] - v) == 1)
		return false;
	return true;
}
void dfs(int x){
	if(x == 11){
		cnt++;
		return;
	}
	for(int i = 0;i<10;i++){
		if(!vis[i]){
			vis[i] = true;
			if(check(x/4,x%4,i)){
				mp[x/4][x%4] = i;
				dfs(x+1);
			}
			vis[i] = false;
		}
	}
}
int main(){
	mp[0][0] = 100;
	dfs(1);
	cout <<cnt<<endl;
	return 0;
} 

7
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题解

#include<iostream>
#include<cstring>
using namespace std;
int a[5];
bool vis[3][4];
int n;
int dir[4][2] = {{0,-1},{-1,0},{1,0},{0,1}};
int ans;
int flag;
void dfs1(int x,int y){
	for(int i = 0;i<4;i++){
		int tx = x + dir[i][0];
		int ty = y + dir[i][1];
		if(tx >= 0 && tx < 3 && ty >= 0 && ty < 4 &&vis[tx][ty]){
			vis[tx][ty] = 0;
			flag++;
			dfs1(tx,ty);
		}
	}
}
void dfs(int k){
	if(n == 5){
		memset(vis,0,sizeof(vis));
		int sx,sy;
		for(int i = 0;i<5;i++){
			int x = (a[i] - 1) / 4;
			int y = (a[i] - 1) % 4;
			vis[x][y] = true;
			if(i == 4){
				vis[x][y] = false;
				sx = x;
				sy = y;
			}
		}
		flag = 1;
		dfs1(sx,sy);
		if(flag == 5){
			ans++;
		}
	}
	else{
		for(int i = k+1;i<=12;i++){
			a[n++] = i;
			dfs(i);
			n--;
		}
	}
}
int main(){
	dfs(0);
	cout <<ans<<endl;
	return 0;
} 

8
四平方和

四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。

比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开

例如,输入:
5
则程序应该输出:
0 0 1 2

再例如,输入:
12
则程序应该输出:
0 2 2 2

再例如,输入:
773535
则程序应该输出:
1 1 267 838

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms

题解

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int vis[5000005];

int main()
{
	int n;
	scanf("%d", &n);
	for(int i=0; i*i <= n; ++i)
		for(int j=0; i*i + j*j <= n; ++j)
			vis[i*i+j*j] = 1;
			
	for(int i=0; i*i <= n; ++i)
		for(int j=i; i*i + j*j <= n; ++j)
		{
			if(vis[n - i*i - j*j])
			{
				for(int k=j; i*i + j*j + k*k <= n; ++k)
				{
					double x = sqrt((double)(n-i*i-j*j-k*k));
					if(x == (int)x) return 0*printf("%d %d %d %d\n", i, j, k, (int)x);
				}
			}
		}	
	return 0;
}
二分思路
#include<iostream>
#include<algorithm>

using namespace std;

const int N=5e6+10;
int n,cnt;

struct node{
    int v,c,d;
    bool operator < (const node &t)const    //重载< 因为sort给结构体排序,括号中的const表示参数a对象不会被修改,最后的const表明调用函数对象不会被修改
    {
        if(v!=t.v)return v<t.v;
        if(c!=t.c)return c<t.c;
        if(d!=t.d)return d<t.d;
    }
}node[N];
int main()
{
    cin>>n;
    for(int c=0;c*c<=n;c++)
        for(int d=c;d*d+c*c<=n;d++)
            node[cnt++]={c*c+d*d,c,d};
            
    sort(node,node+cnt);
    
    for(int a=0;a*a<=n;a++)
        for(int b=a;a*a+b*b<=n;b++)
            {
                int l=0,r=cnt-1;
                int t=n-a*a-b*b;
                while(l<r)// a<b,c<d,ab之后二分查找cd的值,所以一定是最小升序
                    {
                        int mid=l+r>>1;
                        if(node[mid].v>=t)r=mid;
                        else l=mid+1;
                    }
                if(node[l].v==t)
                    {
                        cout<<a<<" "<<b<<" "<<node[l].c<<" "<<node[l].d;
                        return 0;
                    }
            }
}

9
交换瓶子
交换瓶子
来源: 第七届蓝桥杯省赛C++B组
算法标签 图论 环 置换群 贪心
题目描述
有 N 个瓶子,编号 1∼N,放在架子上。

比如有 5 个瓶子:

2 1 3 5 4
要求每次拿起 2 个瓶子,交换它们的位置。

经过若干次后,使得瓶子的序号为:

1 2 3 4 5
对于这么简单的情况,显然,至少需要交换 2 次就可以复位。

如果瓶子更多呢?你可以通过编程来解决。

输入格式
第一行包含一个整数 N,表示瓶子数量。

第二行包含 N 个整数,表示瓶子目前的排列状况。

输出格式
输出一个正整数,表示至少交换多少次,才能完成排序。

数据范围
1≤N≤10000,
1
输入样例1:
5
3 1 2 5 4
1
2
输出样例1:
3
1
输入样例2:
5
5 4 3 2 1
1
2
输出样例2:
2

#include<iostream>
using namespace std;
int a[100],n,ans;
bool vis[100];

int main(){
	cin >>n;
	for(int i = 1;i<=n;i++){
		cin >>a[i];
	}
	for(int i = 1;i<=n;i++){
		if(!vis[i]){
			ans++;
			for(int j = i;!vis[j];j = a[j]){
				vis[j] = true;
							}
		}
	}
	cout <<n-ans<<endl;
} 

10
有点。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值