第一题
计算自然数n至自然数m之间(含n、m)所有整数中的各位数字是奇数的和。如输入n是110,m是118,则结果为1+1+1+1+1+1+1+1+1+3+1+1+1+1+5+1+1+1+1+7+1+1=34。
签到题,循环模拟即可。
public class p1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n, m;
int ans = 0;
n = sc.nextInt();
m = sc.nextInt();
sc.close();
p1 p = new p1();
for (int i = n; i <= m; i++) {
ans += p.oddAdd(i);
}
System.out.println(ans);
}
public int oddAdd(int x) {
int i = 0;
while (x > 0) {
if ((x % 10) % 2 == 1)
i += x % 10;
x = x / 10;
}
return i;
}
}
第二题
当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证通过。
该校验的过程:
1、从卡号最后一位数字开始,逆向将奇数位(1、3、5等等)相加。
2、从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去9),再求和。
3、将奇数位总和加上偶数位总和,结果应该可以被10整除。
例如,卡号是:5432123456788881
则奇数、偶数位(用斜体标出)分布:5 43 21 23 45 67 88 8 8 1
奇数位和=35
偶数位乘以2(有些要减去9)的结果:1 6 2 6 1 5 7 7,求和=35。
最后35+35=70 可以被10整除,认定校验通过。
请编写一个程序,从键盘输入卡号,然后判断是否校验通过。通过显示:“成功”,否则显示“失败”。
比如,用户输入:356827027232780
程序输出:成功
签到题,分奇偶循环模拟即可。
public class p2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
int sum = 0;
for (int i = str.length() - 1; i >= 0; i -= 2) {
sum += Integer.parseInt(str.charAt(i) + "");
}
for (int i = str.length() - 2; i >= 0; i -= 2) {
int temp = Integer.parseInt(str.charAt(i) + "") * 2;
sum += temp > 9 ? temp - 9 : temp;
}
if (sum % 10 == 0)
System.out.println("成功");
else
System.out.println("失败");
}
}
第三题
整数的分划问题。
如,对于正整数n=6,可以分划为:
6
5+1
4+2, 4+1+1
3+3, 3+2+1, 3+1+1+1
2+2+2, 2+2+1+1, 2+1+1+1+1
1+1+1+1+1+1+1
现在的问题是,对于给定的正整数n,编写算法打印所有划分。
用户从键盘输入 n (范围1~10)
程序输出该整数的所有划分。
递归枚举入门题,关于重复的情况我是做了一个判断,比较当前整数剩余部分和上一个值的大小,循环从较小值开始倒序的话,就不会重复了。
public class p3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.close();
p3 p = new p3();
String ans = "";
p.divide(n, n, ans);
}
public void divide(int n, int prev, String ans) {
if (n == 0)
System.out.println(ans);
else {
for (int i = prev < n ? prev : n; i > 0; i--) {
if (ans.isEmpty()) {
divide(n - i, i, ans + i);
} else {
divide(n - i, i, ans + "+" + i);
}
}
}
}
}
第四题
给定一个长度为n的正整数数列A1,A2,... , An 和一个非负整数x,给定m次查询, 每次询问能否从区间[k, r]中选择两个数使得它们的异或等于x。
输入格式:
输入第一行包含三个整数n,m,x。
第二行包含n个正整数A1,A2,...,An。
接下来m行,每行两个整数k,r表示询问区间[k, r]。
输出格式:
对于每个查询, 如果该区间内存在两个数的异或为x则输出yes, 否则输出no。
输入样例:
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
输出样例:
yes
no
yes
no
难点在于异或,Java我不记得有现成方法,那么就得手动实现,寻找的时候做双循环,判断一下一致性就行。
public class p4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int x = sc.nextInt();
p4 p = new p4();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = sc.nextInt();
}
for (int i = 0; i < m; i++) {
int a = sc.nextInt() - 1;
int b = sc.nextInt() - 1;
boolean suc = false;
for (int j = a; j <= b; j++) {
for (int k = a; k <= b; k++) {
if (j != k && p.xor(array[j], array[k]) == x) {
System.out.println("yes");
suc = true;
break;
}
}
if (suc)
break;
}
if (!suc) {
System.out.println("no");
}
}
sc.close();
}
public int xor(int a, int b) {
int i = 0;
int sum = 0;
while (a > 0 || b > 0) {
if (a % 2 == 0 && b % 2 == 1 || a % 2 == 1 && b % 2 == 0)
sum += Math.pow(2, i);
a /= 2;
b /= 2;
i++;
}
return sum;
}
}
第五题
学校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置,数轴上的每个整数点(即0,1,2,……,L)都有一棵树。由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任意区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。请计算将这些树都移走后,马路上还有多少棵树。
输入
500 3
150 300
100 200
470 471
输出
298
(表中输入数据说明:第一行第一个表示区间的总长度,第二个数表示有几个需要移动的区域:例如500 3,表示区间的总长度为[0,500],需要移动的是3个区间,这三个区间分别是[150,300]、[100,200]、[470,471])
比较巧妙的一题,不过也是模版了。
可能有人想到如下的做法:
使用一个可以覆盖所有区间范围的数组,对每个区间进行标记,结果为数组中被标记元素的个数。这种方法的时间复杂度是O(nm)。 注:n是区间个数,m是所有区间总的范围。
但这样的话,时间复杂度其实比较低了,一种更优的思路如下:
使用一个可以覆盖所有区间范围的数组flg,初始化时将数组中的元素都置为0。对于每一个区间[l,r],将flg[l]++,flg[r+1]--。最后使用一个累加器cnt,初始置为0。依次扫描数组中的每一个元素,对于第i个元素,cnt+=flg[i]。此时,若cnt>0,则说明i在某些区间中;若cnt==0,则证明i不在任何区间中。统计cnt==0的元素个数即可。
public class p5 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int l = sc.nextInt();
int n = sc.nextInt();
int cnt = 0, ret = 0;
int[] flg = new int[l+1];
for (int i = 0; i < n; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
flg[a]++;
flg[b + 1]--;
}
for (int i = 0; i <= l; i++) {
cnt += flg[i];
if (cnt == 0) {
ret++;
}
}
System.out.println(ret);
sc.close();
}
}
第六题
一种简单的文件传输加密系统:假设明文一共有m个字节,加密后的密文第1字节和第m字节互换位置,第2字节和第m-2字节互换位置,第3字节和第m-3 字节互换位置,以此类推。互换位置后,每一个字节的第1和第8比特,第2和第7比特,第3和第6比特,第4和第五比特互换位置。为了验证程序正确,输入一个字符串,加密一次后以整数格式输出每个字符,再加密一次后,以整数格式和字符串格式输出第二次加密的内容。
测试用例:
输入“abcde”,则运行结果如下:
edcba
-90 38 -58 70 -122
abcde
97 98 99 100 101
这题其实有点迷惑人,关键在于他题目描述的不清不楚,由于我写这道题的时候时间不多了,所以直接放弃掉了最后一题,考虑到大概率是人工阅卷,这题就按照规范一点的写法完成了。
难点在于对二进制位的处理,这里我直接按照计算逻辑硬写了。
public class p6 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
p6 p = new p6();
String newStr = p.stringReverse(str);
for (int i = 0; i < newStr.length(); i++) {
short temp = (short) newStr.charAt(i);
System.out.print(temp + " ");
}
System.out.println();
String newnewStr = p.stringReverse(newStr);
System.out.println(newnewStr);
for (int i = 0; i < newnewStr.length(); i++) {
short temp = (short) newnewStr.charAt(i);
System.out.print(temp + " ");
}
}
public short bitReverse(int n) {
short i = 7;
short sum = 0;
boolean minus;
if (n % 2 == 1)
minus = true;
else
minus = false;
n /= 2;
i--;
while (n > 0) {
if (n % 2 == 1)
sum += Math.pow(2, i);
n /= 2;
i--;
}
if (minus)
sum -= 128;
return sum;
}
public String stringReverse(String str) {
String newStr = new String();
for (int i = str.length() - 1; i >= 0; i--) {
short tempInt = bitReverse(str.charAt(i));
char temp = (char) tempInt;
newStr += temp;
}
return newStr;
}
}
第七题
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由2021 个结点组成,依次编号1 至2021。
对于两个不同的结点a, b,如果a 和b 的差的绝对值大于21,则两个结点之间没有边相连;如果a 和b 的差的绝对值小于等于21,则两个点之间有一条长度为a 和b 的最小公倍数的无向边相连。
例如:结点1 和结点23 之间没有边相连;结点3 和结点24 之间有一条无向边,长度为24;结点15 和结点25 之间有一条无向边,长度为75。
请计算,结点1 和结点2021 之间的最短路径长度是多少。
这题眼熟,我拿蓝桥杯国二那年,省赛填空题压轴就是这个,这里就不给题解了,各位想了解的话直接看往年题解就行了。