第1题:猜年龄
小明带两个妹妹参加元宵灯会。别人问她们多大了,她们调皮地说:“我们俩的年龄之积是年龄之和的6倍”。小明又补充说:“她们可不是双胞胎,年龄差肯定也不超过8岁啊。”
请你写出:小明的较小的妹妹的年龄。
注意: 只写一个人的年龄数字,请通过浏览器提交答案。不要书写任何多余的内容。
public class Main {
public static void main(String[] args) {
for(int i = 1;i <= 20;i++) { //i 是大妹妹的年龄
for(int j = 1;j < i;j++) { //j 是小妹妹的
if(i - j <= 8 && i * j == (i + j) * 6) {
System.out.println(j);
}
}
}
}
}
第2题:李白打酒
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。
注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。
————————————————————————————————————————————————————————
统计方案数量,一般是深搜
public class Main {
static int ans = 0;
public static void main(String[] args) {
f(5, 9, 2);//5个店,9个花,2斗酒的合理排列的数目
System.out.println(ans);
}
private static void f(int dian, int hua, int jiu) {
if(dian == 0 && hua == 0 && jiu == 1) ans++;//酒得剩一斗,因为最后还得遇一个花
if(dian > 0) f(dian - 1, hua, jiu * 2);//消耗一个店,酒翻倍
if(hua > 0) f(dian, hua - 1, jiu - 1);
}
}
第3题:神奇算式
由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
210 x 6 = 1260
8 x 473 = 3784
27 x 81 = 2187
都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。
请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:列出所有算式)。
——————————————————————————————————————————————————
答案:12
import java.util.Arrays;
public class Main {
static int ans = 0;
public static void main(String[] args) {
for(int i = 1;i <= 9;i++) {
for(int j = 0;j <= 9;j++) {
if(i != j) {
for(int k = 0;k <= 9;k++) {
if(k != i && k != j) {
for(int l = 0;l <= 9;l++) {
if(l != i && l != j && l!= k) {
int src = i * 1000 + j * 100 + k * 10 + l;//i j k l 的四位数
//验证两部分的积,是否由 i j k l 组成
if(j != 0) {//最高位不能是0
int r1 = i * (j * 100 + k * 10 + l);//枚举 * 的位置,1位 * 3位
if(check(src, r1)) {
ans++;
}
}
if(k != 0) {
int r2 = (i * 10 + j) * (k * 10 + l);//枚举 * 的位置,2位 * 2位
//下面这句是为了验证不存在 前部分 = 后部分的情况
// if((i * 10 + j) == (k * 10 + l)) System.out.println(i + " " + j + " " + k + " " + l);
if((i * 10 + j) < (k * 10 + l) && check(src, r2)) { //只验证 前部分 < 后部分的情况,避免交换律
ans++;
}
}
// if(l != 0) { 这个部分,前面 1位 * 3位的时候已经出现过了,只是前后顺序不同,交换律只能算一种
// int r3 = (i * 100 + j * 10 + k) * l;//枚举 * 的位置,3位 * 1位
// if(check(src, r3)) {
// ans++;
// }
// }
}
}
}
}
}
}
}
System.out.println(ans);//也可以无视交换律带来的重复,直接在最后 ans/2
}
private static boolean check(int src, int r) {
//先转字符串
String str = src + "";
String rstr = r + "";
//排序
char[] srcArr = str.toCharArray();
char[] rArr = rstr.toCharArray();
Arrays.sort(srcArr);
Arrays.sort(rArr);
//比较
return Arrays.equals(srcArr, rArr);
}
}
另个版本:
public class Main {
static int ans;//12
public static void main(String[] args) {
for(int a = 1;a <= 9;a++) {
for(int b = 0;b <= 9;b++) {
if(a == b) continue;
for(int c = 0;c <= 9;c++) {
if(c == b || c == a) continue;
for(int d = 0;d <= 9;d++) {
if(d == c || d == b || d == a) continue;
//枚举样例中 x 号的三个位置
int num1 = a * 100 + b * 10 + c;
int num11 = d;
int sum1 = num1 * num11;
if(check(a, b, c, d, sum1)) ans++;
int num2 = a;
int num22 = b * 100 + c * 10 + d;
int sum2 = num2 * num22;
if(check(a, b, c, d, sum2)) ans++;
int num3 = a * 10 + b;
int num33 = c * 10 + d;
int sum3 = num3 * num33;
if(check(a, b, c, d, sum3)) ans++;
}
}
}
}
System.out.println(ans / 2);
}
private static boolean check(int a, int b, int c, int d, int sum) {
String aa = a + "";
String bb = b + "";
String cc = c + "";
String dd = d + "";
String str = sum + "";
if(str.length() != 4) return false;
if(!str.contains(aa)) return false;
if(!str.contains(bb)) return false;
if(!str.contains(cc)) return false;
if(!str.contains(dd)) return false;
return true;
}
}
第4题:写日志
public class Main {
static class A
{
private static int n = 1;
public static void write(String msg)
{
String filename = "t" + n + ".log";
n = n % 3 + 1;//(++n) % 4 == 0 ? 1 : n;
System.out.println("write to file: " + filename + " " + msg);
}
}
public static void main(String[] args) {
for(int i = 0;i < 10;i++) {//循环10次测试
A.write("msg");
}
}
}
第5题:锦标赛
如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发。
如图【1.png】所示,8个选手的锦标赛,先两两捉对比拼,淘汰一半。优胜者再两两比拼…直到决出第一名。
第一名输出后,只要对黄色标示的位置重新比赛即可。
下面的代码实现了这个算法(假设数据中没有相同值)。
代码中需要用一个数组来表示图中的树(注意,这是个满二叉树, 不足需要补齐)。它不是存储数据本身,而是存储了数据的下标。
第一个数据输出后,它所在的位置被标识为-1
class A{
//a 表示待处理的数据,长度如果不是2的次幂,则不足位置补为-1
static void pick(int[] a)
{
int n = 1;
while(n<a.length) n *= 2;
int[] b = new int[2*n-1];
for(int i=0; i<n; i++){
if(i<a.length)
b[n-1+i] = i;
else
b[n-1+i] = -1;
}
//从最后一个向前处理
for(int i=b.length-1; i>0; i-=2){
if(b[i]<0){
if(b[i-1]>=0)
b[(i-1)/2] = b[i-1];
else
b[(i-1)/2] = -1;
}
else{
if(a[b[i]]>a[b[i-1]])
b[(i-1)/2] = b[i];
else
b[(i-1)/2] = b[i-1];
}
}
//输出树根
System.out.println(b[0] + ": " + a[b[0]]);
//值等于根元素的位置需要重新pk
pk(a,b,0,b[0]);
//再次输出树根
System.out.println(b[0] + ": " + a[b[0]]);
}
// a 表示待处理数据,b 二叉树,k 当前要重新比拼的位置,v 已经决胜出的值
static void pk(int[] a, int[] b, int k, int v)
{
int k1 = k*2+1;
int k2 = k1 + 1;
if(k1>=b.length || k2>=b.length){
b[k] = -1;
return;
}
if(b[k1]==v)
pk(a,b,k1,v);
else
pk(a,b,k2,v);
//重新比较
if(b[k1]<0){
if(b[k2]>=0)
b[k] = b[k2];
else
b[k] = -1;
return;
}
if(b[k2]<0){
if(b[k1]>=0)
b[k] = b[k1];
else
b[k] = -1;
return;
}
if(________a[b[k1]] > a[b[k2]]_________) //填空
b[k] = b[k1];
else
b[k] = b[k2];
}
}
请仔细分析流程,填写缺失的代码。
通过浏览器提交答案,只填写缺失的代码,不要填写已有代码或其它说明语句等。
第6题:六角填数
如图【1.png】所示六角形中,填入1~12的数字。
使得每条直线上的数字之和都相同。
图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?
请通过浏览器提交答案,不要填写多余的内容。
——————————————————————————————————————————————————————————
考点:全排列
本题是无重复元素的全排列,有重复的,可以使用set
给这几个空格子编上号,进行全排列的试探
这几条线也编号
public class Main {
static int[] arr = {2,4,5,6,7,9,10,11,12};
public static void main(String[] args) {
f(0);
}
private static void f(int k) {
if(k == 9) {
check();
return ;
}
for(int i = k;i < 9;i++) {
int t = arr[k];
arr[k] = arr[i];
arr[i] = t;
f(k + 1);
t = arr[k];
arr[k] = arr[i];
arr[i] = t;
}
}
private static void check() {
int r1 = 1 + arr[0] + arr[3] + arr[5]; //r1 表示1号线上的和
int r2 = 1 + arr[1] + arr[4] + arr[8];
int r3 = 8 + arr[0] + arr[1] + arr[2];
int r4 = 11 + arr[3] + arr[6];
int r5 = 3 + arr[2] + arr[4] + arr[7];
int r6 = arr[5] + arr[6] + arr[7] + arr[8];
if(r1 == r2 && r2 == r3 && r3 == r4 && r4 == r5 && r5 == r6) {
System.out.println("符合条件的排列为:");
for(int num : arr) {
System.out.print(num + " ");
}
System.out.println();
System.out.println("*处的值为:" + arr[3]);
}
}
}
第7题:绳圈
今有 100 根绳子,当然会有 200 个绳头。
如果任意取绳头两两配对,把所有绳头都打结连接起来。最后会形成若干个绳圈(不考虑是否套在一起)。
我们的问题是:请计算最后将形成多少个绳圈的概率最大?
注意:结果是一个整数,请通过浏览器提交该数字。不要填写多余的内容。
—————————————————————————————————————————————————————————
public class Main {
static double[][] f = new double[101][101];
public static void main(String[] args) {
f[1][1] = 1;
for(int sheng = 2; sheng <= 100;sheng++) {
f[sheng][1] = f[sheng - 1][1] * (sheng - 1) * 2 / (2 * sheng - 1);
for(int quan = 2;quan <= sheng;quan++) {
f[sheng][quan] = (f[sheng - 1][quan - 1] + f[sheng - 1][quan] * (sheng - 1) * 2) / (2 * sheng - 1);
}
}
double p = -1;//概率
int ans = -1;//记录概率最大的相应圈数
//迭代圈
for(int quan = 1;quan <= 100;quan++) {
if(f[100][quan] > p) {
p = f[100][quan];
ans = quan;
}
}
System.out.println(ans);
}
}
第8题:兰顿蚂蚁
兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种。
平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只“蚂蚁”。
蚂蚁的头部朝向为:上下左右其中一方。
蚂蚁的移动规则十分简单:
若蚂蚁在黑格,右转90度,将该格改为白格,并向前移一格;
若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。
规则虽然简单,蚂蚁的行为却十分复杂。刚刚开始时留下的路线都会有接近对称,像是会重复,但不论起始状态如何,蚂蚁经过漫长的混乱活动后,会开辟出一条规则的“高速公路”。
蚂蚁的路线是很难事先预测的。
你的任务是根据初始状态,用计算机模拟兰顿蚂蚁在第n步行走后所处的位置。
【数据格式】
输入数据的第一行是 m n 两个整数(3 < m, n < 100),表示正方形格子的行数和列数。
接下来是 m 行数据。
每行数据为 n 个被空格分开的数字。0 表示白格,1 表示黑格。
接下来是一行数据:x y s k, 其中x y为整数,表示蚂蚁所在行号和列号(行号从上到下增长,列号从左到右增长,都是从0开始编号)。s 是一个大写字母,表示蚂蚁头的朝向,我们约定:上下左右分别用:UDLR表示。k 表示蚂蚁走的步数。
输出数据为两个空格分开的整数 p q, 分别表示蚂蚁在k步后,所处格子的行号和列号。
例如, 输入:
5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5
程序应该输出:
1 3
再例如, 输入:
3 3
0 0 0
1 1 1
1 1 1
1 1 U 6
程序应该输出:
0 0
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
int[][] g = new int[m][n];
for(int i = 0;i < m;i++) {
for(int j = 0;j < n;j++) {
g[i][j] = sc.nextInt();
}
}
int x = sc.nextInt();
int y = sc.nextInt();
String s = sc.next();
int k = sc.nextInt();
sc.close();
int dir = getDir(s);//获取初始位置的方向
int step = 0;
while(true) {
//若蚂蚁在黑格,右转90度,将该格改为白格,并向前移一格
if(g[x][y] == 1) {
dir = dir % 4 + 1;
g[x][y] = 0;
}else {//若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。
dir--;
if(dir == 0) dir = 4;
g[x][y] = 1;
}
//前进一步
if(dir == 1) x--;
if(dir == 2) y++;
if(dir == 3) x++;
if(dir == 4) y--;
step++;
if(step == k) {
System.out.println(x + " " + y);
break;
}
}
}
public static int getDir(String s) {
if(s.equals("U")) return 1;
if(s.equals("R")) return 2;
if(s.equals("D")) return 3;
if(s.equals("L")) return 4;
return 0;
}
}
——————————————————————————————————————————————————
第9题:斐波那契
——————————————————————————————————————————————————————
数据规模小的时候尽量用迭代,规模大的时候用矩阵
import java.math.BigInteger;
import java.util.Scanner;
/**
* 1.由定义fib(n) = fib(n+2)-fib(n+1)
* 2.由1得Σf(n) = f(n+2)-1;
* 如果 m >= n + 2那么f(m) > Σf(n),结果是(f(n+2)-1)%p ( f(m) 要比前面的和大很多,和f(m)取余就没意义了)
* 否则 结果为(f(n+2)-1)%f(m)%p==f(n+2)%f(m)%p-1
* @author
*
*/
public class Main {
public static void main(String[] args) {
// for (int i = 3; i <=10 ; i++) {
// System.out.println(fib(i).longValue());
// }
Scanner sc = new Scanner(System.in);
long n, m, p;
n = sc.nextLong();
m = sc.nextLong();
p = sc.nextLong();
sc.close();
BigInteger bigP = BigInteger.valueOf(p);
if (m >= n + 2) {
BigInteger ans = fib(n + 2, bigP);
System.out.println(ans.mod(bigP).longValue() - 1);
} else {
BigInteger fibm = fib(m);
BigInteger ans = fib(n + 2, fibm);
System.out.println(ans.mod(fibm).mod(bigP).longValue() - 1);
}
}
/*快速矩阵求fib*/
private static BigInteger fib(long m) {
BigInteger[][] ans = mPow(m - 2);
return ans[0][0].add(ans[1][0]);
}
private static BigInteger fib(long m,BigInteger mod) {
BigInteger[][] ans = mPow(m - 2,mod);
return ans[0][0].add(ans[1][0]);
}
/*矩阵快速幂运算*/
private static BigInteger[][] mPow(long n) {
// a 是 1110 矩阵
BigInteger[][] a =
{
{BigInteger.ONE, BigInteger.ONE},
{BigInteger.ONE, BigInteger.ZERO}
};
//单元矩阵
BigInteger[][] ans =
{
{BigInteger.ONE, BigInteger.ZERO},
{BigInteger.ZERO, BigInteger.ONE}
};
while (n != 0) {
if ((n & 1) == 1) {
//结果ans乘以当前平方
BigInteger t1 = ans[0][0];
BigInteger t2 = ans[1][0];
ans[0][0] = ans[0][0].multiply(a[0][0]).add(ans[0][1].multiply(a[1][0]));
ans[0][1] = t1.multiply(a[0][1]).add(ans[0][1].multiply(a[1][1]));
ans[1][0] = ans[1][0].multiply(a[0][0]).add(ans[1][1].multiply(a[1][0]));
ans[1][1] = t2.multiply(a[0][1]).add(ans[1][1].multiply(a[1][1]));
}
//对a进行平方
BigInteger t1 = a[0][0];
BigInteger t2 = a[1][0];
BigInteger t3 = a[0][1];
a[0][0] = a[0][0].multiply(a[0][0]).add(a[0][1].multiply(a[1][0]));
a[0][1] = t1.multiply(a[0][1]).add(a[0][1].multiply(a[1][1]));
a[1][0] = a[1][0].multiply(t1).add(a[1][1].multiply(a[1][0]));
a[1][1] = t2.multiply(t3).add(a[1][1].multiply(a[1][1]));
n >>= 1;
}
return ans;
}
private static BigInteger[][] mPow(long n,BigInteger mod) {
BigInteger[][] a =
{
{BigInteger.ONE, BigInteger.ONE},
{BigInteger.ONE, BigInteger.ZERO}
};
//单元矩阵
BigInteger[][] ans =
{
{BigInteger.ONE, BigInteger.ZERO},
{BigInteger.ZERO, BigInteger.ONE}
};
while (n != 0) {
if ((n & 1) == 1) {
//结果乘以当前平方
BigInteger t1 = ans[0][0];
BigInteger t2 = ans[1][0];
ans[0][0] = ans[0][0].multiply(a[0][0]).add(ans[0][1].multiply(a[1][0])).mod(mod);
ans[0][1] = t1.multiply(a[0][1]).add(ans[0][1].multiply(a[1][1])).mod(mod);
ans[1][0] = ans[1][0].multiply(a[0][0]).add(ans[1][1].multiply(a[1][0])).mod(mod);
ans[1][1] = t2.multiply(a[0][1]).add(ans[1][1].multiply(a[1][1])).mod(mod);
}
//进行平方
BigInteger t1 = a[0][0];
BigInteger t2 = a[1][0];
BigInteger t3 = a[0][1];
a[0][0] = a[0][0].multiply(a[0][0]).add(a[0][1].multiply(a[1][0])).mod(mod);
a[0][1] = t1.multiply(a[0][1]).add(a[0][1].multiply(a[1][1])).mod(mod);
a[1][0] = a[1][0].multiply(t1).add(a[1][1].multiply(a[1][0])).mod(mod);
a[1][1] = t2.multiply(t3).add(a[1][1].multiply(a[1][1])).mod(mod);
n >>= 1;
}
return ans;
}
}
第10题:波动数列
观察这个数列:
1 3 0 2 -1 1 -2 …
这个数列中后一项总是比前一项增加2或者减少3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?
【数据格式】
输入的第一行包含四个整数 n s a b,含义如前面说述。
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。
例如,输入:
4 10 2 3
程序应该输出:
2
【样例说明】
这两个数列分别是2 4 1 3和7 4 1 -2。
【数据规模与约定】
对于10%的数据,1<=n<=5,0<=s<=5,1<=a,b<=5;
对于30%的数据,1<=n<=30,0<=s<=30,1<=a,b<=30;
对于50%的数据,1<=n<=50,0<=s<=50,1<=a,b<=50;
对于70%的数据,1<=n<=100,0<=s<=500,1<=a, b<=50;
对于100%的数据,1<=n<=1000,-1,000,000,000<=s<=1,000,000,000,1<=a, b<=1,000,000。
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms
——————————————————————————————————————————————————————
设首项是 x,则有两种极端情况,全部 +a 或者 全部 -b 的情况,
x, x+a, x+2a, x+3a, x+(n-1)a ==> nx + (0 + 1 + 2 + … + n-1)a ==> nx + (n(n-1)/2)a = s —> x 的最小值 (一路相加等于 s ,所以是最小值)
x, x-b, x-2b, x-3b, x-(n-1)b ==> nx + (0 + 1 + 2 + … + n-1)b ==> nx + (n(n-1)/2)b = s —> x 的最大值 (一路相减等于 s ,所以是最大值)
解法1:枚举首项+深搜(能得20分)
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
private static int n;
private static int s;
private static int a;
private static int b;
private static final int MOD = 100000007;
private static long ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
s = sc.nextInt();
a = sc.nextInt();
b = sc.nextInt();
sc.close();
int x = 0;
//枚举首项
int min = (s - a * n * (n - 1) / 2) / n - 1;//为了确保能枚举到边界,可以扩大1
int max = (s + b * n * (n - 1) / 2) / n + 1;
for(x = min;x <= max;x++) {
List<Integer> path = new ArrayList<>();
path.add(x);
dfs(x, 1, x, path);
}
System.out.println(ans);
}
/**
*
* @param x 上一项
* @param cnt 截止到上一项已经有多少个
* @param sum 截止到上一项已经求得的和
*/
private static void dfs(int x, int cnt, int sum, List<Integer> path) {
if(cnt == n) {
if(sum == s) {
ans++;
// for(int num : path) { 输出合理的路径
// System.out.print(num + " ");
// }
// System.out.println();
}
if(sum > MOD) sum %= MOD;
return ;
}
path.add(x + a);
dfs(x + a, cnt + 1, sum + x + a, path);
path.remove(path.size() - 1);
path.add(x - b);
dfs(x - b, cnt + 1, sum + x - b, path);
path.remove(path.size() - 1);
}
}
最终解法:
转化为 01背包,用 dp 做
import java.util.Scanner;
public class Main {
private static int n;
private static long s;
private static long a;
private static long b;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
s = sc.nextLong();
a = sc.nextLong();
b = sc.nextLong();
sc.close();
int t = n * (n - 1) / 2;
int[] dp = new int[t + 1];
dp[0] = 1;
for (int i = 1; i <= n - 1; i++) {
for (int j = i * (i + 1) / 2; j >= i; j--) {
// dp[j] += dp[j - i];
// if (dp[j] > 100000007) dp[j] %= 100000007;
dp[j] = (dp[j] + dp[j - i]) % 100000007;
}
}
long ans = 0;
for (int i = 0; i <= t; i++) {
if ((s - i * a + (t - i) * b) % n == 0)
ans = (ans + dp[i]) % 100000007;
// if (ans > 100000007) ans %= 100000007;
}
System.out.println(ans);
}
}