第一题:武功秘籍
小明到X山洞探险,捡到一本有破损的武功秘籍(2000多页!当然是伪造的)。
他注意到:书的第10页和第11页在同一张纸上,但第11页和第12页不在同一张纸上。
小明只想练习该书的第81页到第92页的武功,又不想带着整本书。请问他至少要撕下多少张纸带走?
这是个整数,请通过浏览器提交该数字,不要填写任何多余的内容。
答案:7
第二题:切面条
一根高筋拉面,中间切一刀,可以得到2根面条。如果先对折1次,
中间切一刀,可以得到3根面条。如果连续对折2次,中间切一刀,可以得到5根面条。
那么,连续对折10次,中间切一刀,会得到多少面条呢?
答案是个整数,请通过浏览器提交答案。不要填写任何多余的内容。
找规律
切n刀时,可以得到2的n次方加1跟面条
答案:1025
第三题: 猜字母
把abcd…s共19个字母组成的序列重复拼接106次,得到长度为2014的串。
接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母。
得到的新串再进行删除奇数位置字母的动作。如此下去,最后只剩下一个字母,请写出该字母。
答案是一个小写字母,请通过浏览器提交答案。不要填写任何多余的内容。
答案:q
public static void main(String[] args){
char[] a=new char[2014];
int index=0;
for(int i=1;i<=106;i++){
for(int j=0;j<19;j++){
a[index++]=(char)('a'+j);
}
}
int len=2014;
while(len!=1){
int k=0;
for(int i=1;i<len;i+=2){
a[k++]=a[i];
}
len=k;
}
System.out.println(a[0]);
}
第四题: 大衍数列
中国古代文献中,曾记载过“大衍数列”, 主要用于解释中国传统文化中的太极衍生原理。
它的前几项是:0、2、4、8、12、18、24、32、40、50 …
其规律是:对偶数项,是序号平方再除2,奇数项,是序号平方减1再除2。
以下的代码打印出了大衍数列的前 100 项。
for(int i=1; i<100; i++) {
if(________________) //填空
System.out.println(ii/2);
else
System.out.println((ii-1)/2);
}
请填写划线部分缺失的代码。通过浏览器提交答案。
注意:不要填写题面已有的内容,也不要填写任何说明、解释文字
答案:i%2==0
第五题:圆周率
数学发展历史上,圆周率的计算曾有许多有趣甚至是传奇的故事。
其中许多方法都涉及无穷级数。
如图所示,就是一种用连分数的形式表示的圆周率求法。
下面的程序实现了该求解方法。实际上数列的收敛对x的初始值 并不敏感。
结果打印出圆周率近似值(保留小数点后4位,并不一定与圆周率真值吻合)。
double x = 111;
for(int n = 10000; n>=0; n–){
int i = 2 * n + 1;
x = 2 + (i*i / x);
}
System.out.println(String.format("%.4f", ______________));
答案:4/(x-1)
第六题:奇怪的分式
上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:1/4 乘以 8/5
小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45
老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!
对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?
请写出所有不同算式的个数(包括题中举例的)。
显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。
但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!
注意:答案是个整数(考虑对称性,肯定是偶数)。请通过浏览器提交。不要书写多余的内容。
答案:14
static int ans;
public static void main(String[] args){
for(int a=1;a<=9;a++){
for(int b=1;b<=9;b++){
if(b==a)continue;
for(int c=1;c<=9;c++){
for(int d=1;d<=9;d++){
if(d==c)continue;
int g1=gcd(a*c,b*d);
int g2=gcd(a*10+c,b*10+d);
if((a*c)/g1==(a*10+c)/g2 && (b*d)/g1==(b*10+d)/g2){
ans++;
}
}
}
}
}
System.out.println(ans);
}
//求a,b的最大公约数
static int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
第七题:扑克序列
A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。
请填写出所有符合要求的排列中,字典序最小的那个。
例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。
请通过浏览器提交答案。“A”一定不要用小写字母a,也不要用“1”代替。
字符间一定不要留空格。
答案:2342A3A4
static char[] a={'A','A','2','2','3','3','4','4'};
static Set<String> set=new HashSet<>();
public static void main(String[] args){
f(0);
for(String s:set){
System.out.println(s);
}
}
static void f(int k){
if(k==8){
String s=new String(a);
if(check(s)){
set.add(s);
}
}
for(int i=k;i<8;i++) {
char t = a[k];
a[k] = a[i];
a[i] = t;
f(k + 1);
t = a[k];
a[k] = a[i];
a[i] = t;
}
}
static boolean check(String s){
if(s.lastIndexOf('A')-s.indexOf('A')==2&&
s.lastIndexOf('2')-s.indexOf('2')==3&&
s.lastIndexOf('3')-s.indexOf('3')==4&&
s.lastIndexOf('4')-s.indexOf('4')==5
)return true;
return false;
}
第八题:分糖果
问题描述
有n个小朋友围坐成一圈。老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:
每个小朋友都把自己的糖果分一半给左手边的孩子。
一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数。
反复进行这个游戏,直到所有小朋友的糖果数都相同为止。
你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。
输入格式
程序首先读入一个整数N(2 < N < 100),表示小朋友的人数。
接着是一行用空格分开的N个偶数(每个偶数不大于1000,不小于2)
输出格式
要求程序输出一个整数,表示老师需要补发的糖果数。
样例输入
3
2 2 4
样例输出
4
分析:
每一轮中:
每个小朋友都把自己的糖果分一半给左手边的孩子。可以遍历数组,从数组的第二个数开始,将自己的一半分给前一个位置的数。
for (int i = 1; i < n; i++) {
a[i - 1] = a[i - 1] / 2 + a[i] / 2;
}
需要注意的是,要在每一轮的开始,先保存一下a[0]的值,因为最后a[0]要分一半的糖果给a[n-1],如果不保存,那么最后算a[n-1]时,a[0]分给a[n-1]一半的糖果,但是此时的a[0]已经不是最开始的数量了,而是a[1]分一半给a[0]之后的数量。
每一轮每个孩子分完糖果之后就判断一下是否是奇数个糖果,如果是奇数个糖果,那么就再给他补发一个糖果,用ans记录补发给孩子的糖果
static int n;
static int[] a;
static int ans;
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
a=new int[n];
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
}
while(check(a)) {
int t = a[0];
for (int i = 1; i < n; i++) {
a[i - 1] = a[i - 1] / 2 + a[i] / 2;
if (a[i - 1] % 2 != 0) {
a[i - 1] = a[i - 1] + 1;
ans++;
}
}
a[n - 1] = a[n - 1] / 2 + t / 2;
if (a[n - 1] % 2 != 0) {
a[n - 1] = a[n - 1] + 1;
ans++;
}
}
System.out.println(ans);
}
static boolean check(int[] a){
int c=a[0];
for(int i=1;i<n;i++){
if(a[i]!=c)
return true;
}
return false;
}
第九题:地宫取宝
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,
小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
【数据格式】
输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,
输出它对 1000000007 取模的结果。
例如,输入:
2 2 2
1 2
2 1
程序应该输出:
2
再例如,输入:
2 3 2
1 2 3
2 1 5
程序应该输出:
14
解决方案1(简单递归,只能解决一部分问题):
从左上角开始进行递归 每次都有两种选择,向下走或者向右走。
当走到右下角时,判断当前手里的物品数量与k是否相等。如果相等,则将记录结果的ans加一。
要注意的一点是:
if((cnt==k)||(cnt==k-1&&cur>max))
因为当递归到右下角时,右下角的那个位置上的物品还没有取,此时如果小明手里的物品数为k-1,并且这个物品的重量大于小明手里所有物品的重量,那么小明取上这个物品刚好可以满足条件,所以这也算一种情况,不能忽略
static int MOD=1000000007;
static long ans;
static int[][] a;
static int n,m,k;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
a=new int[n][m];
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
a[i][j]=sc.nextInt();
}
}
dfs(0,0,-1,0);//第一个价值可能为0,所以当前最大价值设置初始值为-1
System.out.println(ans);
}
//max为当前手里的最大值,cnt为手里物品的数量
static void dfs(int x,int y,int max,int cnt) {
if(x==n||y==m||cnt>k) {
return;
}
int cur=a[x][y];
if(x==n-1&&y==m-1) {
if((cnt==k)||(cnt==k-1&&cur>max)) {
ans++;
if(ans>MOD)ans%=MOD;
}
}
if(cur>max) {//当价值大于手里当前的最大值时,可以选择取
dfs(x+1, y, cur, cnt+1);
dfs(x, y+1, cur, cnt+1);
}
//对于价值较小,或者价值较大但不取
dfs(x+1, y, max, cnt);
dfs(x, y+1, max, cnt);
}
解决方案2(记忆型递归,能解决所有数据):
记忆型递归的思路是:
在递归的基础上,用一个数组来记录当前的状态,
比如当x=1,y=1,max=1,cnt=1这种情况已经计算过了,那么就把这种情况的存入到数组cache当中。
先初始化cache为-1 ,那么当在递归时,就可以先判断当前的情况是否已经计算过。
如果计算过,那么cache[x][y][max][cnt]的值不等于-1
就直接返回cache之前缓存当前状态的值即可,而不必再重复计算这种情况。
简单点来说,比如当前x=1,y=1,sum=1,cnt=1。之前已经计算过此种情况到右下角满足题意的情况有5种,那么当别的递归情况递归到x=1,y=1,sum=1,cnt=1时,直接返回5即可,不用再重复递归。
static int MOD=1000000007;
static int[][] a;
static int n,m,k;
static long[][][][] chche=new long[51][51][14][14];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
a=new int[n][m];
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
a[i][j]=sc.nextInt();
}
}
for(int i=0;i<51;i++) {
for(int j=0;j<51;j++) {
for(int q=0;q<14;q++) {
for(int w=0;w<14;w++) {
chche[i][j][q][w]=-1;
}
}
}
}
//第一个价值可能为0,所以当前最大价值设置初始值为-1
long ans=dfs(0,0,-1,0);
System.out.println(ans);
}
//max为当前手里的最大值,cnt为手里物品的数量
static long dfs(int x,int y,int max,int cnt) {
//判断max+1而不是max的原因是因为max初始的时候为-1 如果不加1,会出现越界
if(chche[x][y][max+1][cnt]!=-1)return chche[x][y][max+1][cnt];
if(x==n||y==m||cnt>k) return 0;
int cur=a[x][y];
long ans=0;
if(x==n-1&&y==m-1) {
if((cnt==k)||(cnt==k-1&&cur>max)) {
return 1;
}
return 0;
}
if(cur>max) {//当价值大于手里当前的最大值时,可以选择取
ans=(ans+dfs(x+1, y, cur, cnt+1))%MOD;
ans=(ans+dfs(x, y+1, cur, cnt+1))%MOD;
}
//对于价值较小,或者价值较大但不取
ans=(ans+dfs(x+1, y, max, cnt))%MOD;
ans=(ans+dfs(x, y+1, max, cnt))%MOD;
chche[x][y][max+1][cnt]=ans%MOD;
return ans;
}
第十题:矩阵翻硬币
小明先把硬币摆成了一个 n 行 m 列的矩阵。
随后,小明对每一个硬币分别进行一次 Q 操作。
对第x行第y列的硬币进行 Q 操作的定义:将所有第 ix 行,第 jy 列的硬币进行翻转。
其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。
当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。
小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。
聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。
然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。
【数据格式】
输入数据包含一行,两个正整数 n m,含义见题目描述。
输出一个正整数,表示最开始有多少枚硬币是反面朝上的。
【样例输入】
2 3
【样例输出】
1
【数据规模】
对于10%的数据,n、m <= 10^3;
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于10%的数据,n、m <= 10^1000(10的1000次方)。
分析:
求1-N里面有多少个平方数
可以对n开平方取整 比如 9里面有 1 4 9 三个
将所有第 ix 行,第 jy 列的硬币进行翻转
比如i j分别为2 3时 那么4x 3y 4x 6y等等都要进行翻转
现在定位在一个点上
假设现在已经全部进行完Q操作
如果这个点翻了奇数次,就可以判断出此硬币开始为反面
怎么判断这个点为奇数次呢?
可以通过坐标x y,因为只要是遇到x或者是y的真因子为坐标,
那么这个点就要被翻一次,比如说x=9,9的真因子有1,3,9,
遇到这个三个数,这个点都要翻一次
如果这个点的x y的真因子为奇数个
奇数乘以奇数为奇数 即总共被翻的次数为奇数
怎么判断这个点x y的真因子都为奇数个呢?
如果 x y都为平方数 那么真因子为奇数个 比如9的真因子为 1 3 9
12的真因子数为1 2 3 4 6 12
所以到此 这道题就是找出1-x 1-y中平方数和的乘积
就是x所包含的平方数 加上y包含的平方数
(数学知识)n包含的平方数总和为对n开方
比如 16包含 1 4 9 16四个 对16开方就是4 17开方也是4
(数学知识) 一个数开方 如果长度为n 12的长度为2
当n为奇数时,其开方之后长度为n/2 + 1
偶数时,开方之后长度为n
由于题上给的数据很大,可以用BigInteger来做
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s1=sc.next();
String s2=sc.next();
System.out.println(sqrt(s1).multiply(sqrt(s2)));
}
private static BigInteger sqrt(String s) {
int length=s.length();
int len=0;
if(length%2==0) {
len=length/2;
}else {
len=length/2+1;
}
char[] sArr=new char[len];
Arrays.fill(sArr, '0');
BigInteger target=new BigInteger(s);
for(int pos=0;pos<len;pos++) {
for(char c='1';c<='9';c++) {
sArr[pos]=c; //在pos这个位置试着填入1-9
BigInteger pow=new BigInteger(String.valueOf(sArr)).pow(2);//平方
//如果pow比s大
if(pow.compareTo(target)==1) {
sArr[pos]-=1;
break;
}
}
}
return new BigInteger(String.valueOf(sArr));
}