2017年蓝桥杯模拟赛

1.标题:算年龄


英国数学家德摩根出生于19世纪初叶(即18xx年)。
他年少时便很有才华。一次有人问他的年龄,他回答说:
“到了x的平方那年,我刚好是x岁”。


请你计算一下,德摩根到底出生在哪一年。
题中的年龄指的是周岁。


请填写表示他出生年份的四位数字,不要填写任何多余内容。

思路:通过计算器计算,只有43,44这2个数字符合要求,42*42=1764,45*45=2025

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		for (int i=43; i<45; i++) {
			int year = i * i - i;
			//1806
			//1892
			System.out.println(year);
		}
	}
}
因为是19世纪初叶,所以是1806


2.题目:猜算式


你一定还记得小学学习过的乘法计算过程,比如:


   273
x   15
------
  1365
  273
------
  4095
  
请你观察如下的乘法算式


    ***
x   ***
--------
    ***
   ***
  ***
--------
  *****
  
星号代表某位数字,注意这些星号中,
0~9中的每个数字都恰好用了2次。
(如因字体而产生对齐问题,请参看图p1.jpg)


请写出这个式子最终计算的结果,就是那个5位数是多少?


注意:只需要填写一个整数,不要填写任何多余的内容。比如说明文字。


import java.util.Arrays;

public class Main {

	static int[] num = new int[3];
	static int[] visit = new int[10];
	public static void main(String[] args) {
		for (int i=100; i<=999; i++) {
			num[0] = i % 10;
			num[1] = i / 10 % 10;
			num[2] = i / 100;
			for (int j=100; j<=999; j++) {
				Arrays.fill(visit, 0);
				cal2(i);
				cal2(j);
				//中间计算过程的积都是三位数,则继续进行
				if (cal(j % 10) && cal(j / 10 % 10) && cal(j / 100)) {
					cal2(i * j);
					int k;
					for (k=0; k<10; k++) {
						if (visit[k] != 2)
							break;
					}
					if (k == 10) {
						//179*224=40096
						System.out.println(i + "*" + j + "=" + i * j);
					}
				}
			}
		}
	}
	//标记因子和积的各个位数
	private static void cal2(int x) {
		while (x != 0) {
			visit[x % 10]++;
			x /= 10;
		}
	}
	//标记中间计算过程的各个位数,如果中间计算过程中有积为4位数,则返回false
	private static boolean cal(int x) {
		int temp = 0;
		for (int i=0; i<3; i++) {
			int y = num[i] * x + temp;
			temp = y / 10;
			if (i == 2 && temp != 0)
				return false;
			visit[y % 10]++;
		}
		return true;
	}
}

3.标题: 排列序数


X星系的某次考古活动发现了史前智能痕迹。
这是一些用来计数的符号,经过分析它的计数规律如下:
(为了表示方便,我们把这些奇怪的符号用a~q代替)


abcdefghijklmnopq 表示0
abcdefghijklmnoqp 表示1
abcdefghijklmnpoq 表示2
abcdefghijklmnpqo 表示3
abcdefghijklmnqop 表示4
abcdefghijklmnqpo 表示5
abcdefghijklmonpq 表示6
abcdefghijklmonqp 表示7
.....


在一处石头上刻的符号是:
bckfqlajhemgiodnp


请你计算出它表示的数字是多少?


请提交该整数,不要填写任何多余的内容,比如说明或注释。

思路:暴力模拟时间太长,用康托展开

X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! ,其中a[i]为当前未出现的元素中是排在第几个(从0开始)。这就是康托展开


{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。123 132 213 231 312 321 。

代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。
他们间的对应关系可由康托展开来找到。
如我想知道321是{1,2,3}中第几个小的数可以这样考虑 :
第一位是3,当第一位的数小于3时,那 排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个小的数。 2*2!+1*1!+0*0!就是康托展开。
再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个小数。
a[i]的表述可能和最开始的表述有点差别,但效果是一样的
public class Main {
	
	public static void main(String[] args) {
		long[] a = new long[18];
		a[0] = 1;
		for (int i=1; i<=17; i++) {
			a[i] = a[i-1] * i;
		}
		long total = 0;
		String str = "bckfqlajhemgiodnp";
		for (int i=0; i<17; i++) {
			int sum = 0;
			//求第i个元素在未出现的元素中排名第几
			for (int j=i+1; j<17; j++) {
				if (str.charAt(j) < str.charAt(i))
					sum++;
			}
			total += sum * a[16-i];
		}
		//22952601027516
		System.out.println(total);
	}
}

4.标题:字符串比较


我们需要一个新的字符串比较函数compare(s1, s2).
对这个函数要求是:
1. 它返回一个整数,表示比较的结果。
2. 结果为正值,则前一个串大,为负值,后一个串大,否则,相同。
3. 结果的绝对值表示:在第几个字母处发现了两个串不等。


下面是代码实现。对题面的数据,结果为:
-3
2
5


仔细阅读源程序,填写划线位置缺少的代码。


-------------------------------------------------
Java语言代码:


static int compare(String s1, String s2)
{
if(s1==null && s2==null) return 0;
if(s1==null) return -1;
if(s2==null) return 1;

if(s1.isEmpty() && s2.isEmpty()) return 0;
if(s1.isEmpty()) return -1;
if(s2.isEmpty()) return 1;

char x = s1.charAt(0);
char y = s2.charAt(0);

if(x<y) return -1;
if(x>y) return 1;

int t = compare(s1.substring(1),s2.substring(1));
if(t==0) return 0;

return ____________________ ; //填空位置
}


public static void main(String[] args)
{
System.out.println(compare("abc", "abk"));
System.out.println(compare("abc", "a"));
System.out.println(compare("abcde", "abcda"));
}


---------------------------
C/C++ 语言代码:
int compare(const char* s1, const char* s2)
{
if(s1==NULL && s2==NULL) return 0;
if(s1==NULL) return -1;
if(s2==NULL) return 1;

if(*s1 == 0 && *s2== 0) return 0;
if(*s1 == 0) return -1;
if(*s2 == 0) return 1;

if(*s1<*s2) return -1;
if(*s1>*s2) return 1;

int t = compare(s1+1,s2+1);
if(t==0) return 0;

return __________________________; //填空位置
}




int main()
{
printf("%d\n", compare("abc","abk"));
printf("%d\n", compare("abc","a"));
printf("%d\n", compare("abcde","abcda"));
return 0;
}


注意:
只提交划线部分缺少的代码,不要包含已经存在的代码或符号。
也不要画蛇添足地写出任何注释或说明性文字。


注意选择你所使用的语言。
//注意把符号写在前面
return t > 0 ? ++t : --t;

5.标题: 还款计算


银行贷款的等额本息还款方法是:
每月还固定的金额,在约定的期数内正好还完(最后一个月可能会有微小的零头出入)。


比如说小明在银行贷款1万元。贷款年化利率为5%,贷款期限为24个月。
则银行会在每个月进行结算:
结算方法是:计算本金在本月产生的利息: 本金 x (年利率/12)
则本月本金结余为:本金 + 利息 - 每月固定还款额
计算结果会四舍五入到“分”。


经计算,此种情况下,固定还款额应为:438.71


这样,第一月结算时的本金余额是:
9602.96
第二个月结算:
9204.26
第三个月结算:
8803.9
....
最后一个月如果仍按固定额还款,则最后仍有0.11元的本金余额,
但如果调整固定还款额为438.72, 则最后一个月会多还了银行0.14元。
银行会选择最后本金结算绝对值最小的情况来设定 每月的固定还款额度。
如果有两种情况最后本金绝对值相同,则选择还款较少的那个方案。


本题的任务是已知年化利率,还款期数,求每月的固定还款额度。


假设小明贷款为1万元,即:初始本金=1万元。
年化利率的单位是百分之多少。
期数的单位为多少个月。


输入为2行,
第一行为一个小数r,表示年率是百分之几。(0<r<30)
第二行为一个整数n,表示还款期限。 (6<=n<=120)


要求输出为一个整数,表示每月还款额(单位是:分)


例如:
输入:
4.01
24


程序应该输出:
43429


再比如:
输入:
6.85
36


程序应该输出:
30809


资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms




请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。


所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
java选手注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
java选手注意:主类的名字必须是:Main,否则按无效代码处理。


c/c++选手注意: main函数需要返回0
c/c++选手注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
c/c++选手注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。


提交程序时,注意选择所期望的语言类型和编译器类型
6.题目:滑动解锁


滑动解锁是智能手机一项常用的功能。你需要在3x3的点阵上,从任意一个点开始,反复移动到一个尚未经过的"相邻"的点。这些划过的点所组成的有向折线,如果与预设的折线在图案、方向上都一致,那么手机将解锁。


所谓两个点“相邻”:当且仅当以这两个点为端点的线段上不存在尚未经过的点。


此外,许多手机都约定:这条折线还需要至少经过4个点。


为了描述方便,我们给这9个点从上到下、从左到右依次编号1-9。即如下排列:


1 2 3
4 5 6
7 8 9


那么1->2->3是非法的,因为长度不足。
1->3->2->4也是非法的,因为1->3穿过了尚未经过的点2。
2->4->1->3->6是合法的,因为1->3时点2已经被划过了。


某大神已经算出:一共有389112种不同的解锁方案。没有任何线索时,要想暴力解锁确实很难。
不过小Hi很好奇,他希望知道,当已经瞥视到一部分折线的情况下,有多少种不同的方案。
遗憾的是,小Hi看到的部分折线既不一定是连续的,也不知道方向。


例如看到1-2-3和4-5-6,
那么1->2->3->4->5->6,1->2->3->6->5->4, 3->2->1->6->5->4->8->9等都是可能的方案。




你的任务是编写程序,根据已经瞥到的零碎线段,求可能解锁方案的数目。


输入:
每个测试数据第一行是一个整数N(0 <= N <= 8),代表小Hi看到的折线段数目。
以下N行每行包含两个整数 X 和 Y (1 <= X, Y <= 9),代表小Hi看到点X和点Y是直接相连的。


输出:
对于每组数据输出合法的解锁方案数目。




例如:
输入:
8
1 2 2 3
3 4 4 5
5 6 6 7
7 8 8 9


程序应该输出:
2


再例如:
输入:
4
2 4
2 5
8 5
8 6


程序应该输出:
258




资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms




请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。


所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
java选手注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
java选手注意:主类的名字必须是:Main,否则按无效代码处理。


c/c++选手注意: main函数需要返回0
c/c++选手注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
c/c++选手注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。


提交程序时,注意选择所期望的语言类型和编译器类型。

发布了477 篇原创文章 · 获赞 34 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/qq_25605637/article/details/67633426