2015 蓝桥杯省赛部分题整理(九数组分数,牌型种数,串逐位和,循环节长度,打印菱形)

1.九数组分数
题目描述:
1,2,3…9 这九个数字组成一个分数,其值恰好为1/3,如何组法?
下面的程序实现了该功能,请填写划线部分缺失的代码。

思路:不难看出这个程序在模拟全部数字的排列情况,用的是搜索与回溯算法,让每一位去与其后面的数字做交换,代码段缺少的部分正是回溯的部分,再做一次交换即可;

#include <stdio.h>

void test(int x[])
{
	int a = x[0]*1000 + x[1]*100 + x[2]*10 + x[3];
	int b = x[4]*10000 + x[5]*1000 + x[6]*100 + x[7]*10 + x[8];
	
	if(a*3==b) printf("%d / %d\n", a, b);
}

void f(int x[], int k)
{
	int i,t;
	if(k>=9){
		test(x);
		return;
	}	
	for(i=k; i<9; i++){
		{t=x[k]; x[k]=x[i]; x[i]=t;}
		f(x,k+1);
		_____________________________________________ // 填空处
	}
}
int main()
{
	int x[] = {1,2,3,4,5,6,7,8,9};
	f(x,0);	
	return 0;
}

答案:{t=x[k]; x[k]=x[i]; x[i]=t;}

2.牌型种数

题目描述:
小明被劫持到X赌城,被迫与其他3人玩牌。
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
这时,小明脑子里突然冒出一个问题:
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?
输出:
能拿到的初始牌型组合数量;

思路:
一开始以为是一个组合数的问题,但是一直不知道怎么去除重复的部分,后来才知道就是一个暴力的搜索问题,在不考虑花色和顺序的情况下,只要考虑每个点数的张数即可,即用 每类四张的牌去组合成十三张牌看有多少种组合情况,可以用dfs来写,也可以写多重循环,这里只会给出多重循环的写法,对dfs有兴趣的可自行尝试;

代码

#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
typedef long long ll;

const ll maxx = 1e18;
const int N = 1e4+10;
const int p = 1e4;
const double eps = 1e-8;

int cnt;

int main()
{
	for(int i=0;i<=4;i++)//1 
	{
		for(int j=0;j<=4;j++)//2
		{
			for(int k=0;k<=4;k++)//3 
			{
				for(int l=0;l<=4;l++)//4 
				{
					for(int m=0;m<=4;m++)//5
					{
						for(int n=0;n<=4;n++)//6
						{
							for(int s=0;s<=4;s++)//7
							{
								for(int q=0;q<=4;q++)//8
								{
									for(int w=0;w<=4;w++)//9
									{
										for(int e=0;e<=4;e++)//10
										{
											for(int r=0;r<=4;r++)//11
											{
												for(int t=0;t<=4;t++)//12
												{
													for(int y=0;y<=4;y++)//13
													{
														if(i+j+k+l+m+n+s+q+w+e+r+t+y==13)
															cnt++;
													}		
												}		
											}		
										}	
									}
								}	
							}	
						}	
					} 
				}
			}	
		}	
	}	

	cout<<cnt;
}

答案:3598180;
3.串逐位和
描述:
给定一个由数字组成的字符串,我们希望得到它的各个数位的和。
比如:“368” 的诸位和是:17
这本来很容易,但为了充分发挥计算机多核的优势,小明设计了如下的方案:

int f(char s[], int begin, int end)
{
	int mid;
	if(end-begin==1) return s[begin] - '0';
	mid = (end+begin) / 2;
	return ____________________________________;  //填空
}
int main()
{
	char s[] = "4725873285783245723";
	printf("%d\n",f(s,0,strlen(s)));
	return 0;
}

思路:一个典型的分治思路;
就是把大的问题分解成子问题解决

一开始随便写了写,写的是

return f(s,begin,mid)+f(s,mid+1,end);

但是这是错的,用例子说明他为什么是错的

1.奇数长度串
111
(0,3) -> (0,1) 与 (2,3)
这样只能记录 第一个 1 和第三个 1,漏掉了第二个 1;
2.偶数长度串
1111
(0,4) -> (0,2) 与 (3,4) -> (0,1) 与 (1,2) 与 (3,4)
漏掉了第三个 1;

正确答案是:

return f(s,begin,mid)+f(s,mid,end);

1.奇数长度串
111
(0,3) -> (0,1) 与 (1,3) -> (0,1) 与 (1,2) 与 (2,3)
2.偶数长度串
1111
(0,4) -> (0,2) 与 (2,4) -> (0,1) 与 (1,2) 与 (2,3) 与 (3,4)
全部计算到;

所以正确答案就是

return f(s,begin,mid)+f(s,mid,end);

4.循环节长度
题目描述:
两个整数做除法,有时会产生循环小数,其循环部分称为:循环节。
比如,11/13=6=>0.846153846153… 其循环节为[846153] 共有6位。
下面的方法,可以求出循环节的长度。

请仔细阅读代码,并填写划线部分缺少的代码。

public static int f(int n, int m)
	{
		n = n % m;	
		Vector v = new Vector();
		
		for(;;)
		{
			v.add(n);
			n *= 10;
			n = n % m;
			if(n==0) return 0;
			if(v.indexOf(n)>=0)  _________________________________ ;  //填空
		}
	}

思路:
当循环中的任意两个位置的除数相等的时候其后的循环序列必然相等,有相同的的循环节就说明除数相等,去模拟整除并存入每一位的除数,找到相等的除数,两个相等除数之间的距离即为循环节长度。
注意这个题容易写成

return v.size()

这个错误答案,因为小数不一定是在小数点后就开始循环,比如1.2313313313…
我们要求的是两个相等除数之间的距离
故正确答案是:

return v.size() - v.indexOf(n)

5.打印菱形
描述:
给出菱形的边长,在控制台上打印出一个菱形来。
为了便于比对空格,我们把空格用句点代替。
当边长为8时,菱形为:

.......*
......*.*
.....*...*
....*.....*
...*.......*
..*.........*
.*...........*
*.............*
.*...........*
..*.........*
...*.......*
....*.....*
.....*...*
......*.*
.......*

下面的程序实现了这个功能,但想法有点奇怪。
请仔细分析代码,并填写划线部分缺失的代码。

public class A
{
	public static void f(int n)
	{
		String s = "*";
		for(int i=0; i<2*n-3; i++) s += ".";
		s += "*";
	
		String s1 = s + "\n";
		String s2 = "";
		
		for(int i=0; i<n-1; i++){
			//System.out.println("=>"+s);
			s = "." + _____________________________________ + "*";  //填空
			s1 = s + "\n" + s1;
			s2 += s + "\n";
		}
		System.out.println(s1+s2);		
	}
	public static void main(String[] args)
	{
		f(8);
	}
}

思路:虽然是一道Java的题,但还是看看思路,最后打印的是串
s1+s2 再看中间的操作过程,可以推出
s1是中间一行+上半部分
s2是中间一行+下半部分

循环过程就是累加过程
每次循环规律相同,我们举出一组循环来看
*.............*.*...........*
函数中给出了开头的".“和结尾的”*"我们只需要
*.............*变成*...........
每次变换删去最后三个元素
结合Java string类型的函数就能推出答案是

s.substring(0,s.length()-3)

substring(first,last) 返回
[first,last]之间的字串

结语:

马山蓝桥杯了,蓝桥杯加油!!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草莓猫猫软糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值