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>, 不能通过工程设置而省略常用头文件。


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