NENU 蓝桥杯训练赛(简单模拟+思维)题解
A Chocolate Thief
题意:
有 n n n 个学生,每个学生有一块巧克力, x , y , z x,y,z x,y,z 为巧克力的长、宽、高 。每个学生的巧克力长、宽、高可能不同,但体积是相同的。假设学生里最多有一个小偷,如果有小偷,他从另一个学生那里拿走了一部分巧克力。问是否有小偷?
思路:
找到体积的最大值 M a x Max Max 和最小值 M i n Min Min 。如果 M a x = = M i n Max == Min Max==Min ,则没有小偷;否则, 体积为 M a x Max Max 的学生偷了体积为 M i n Min Min 的学生的巧克力。
import java.util.*;
import java.math.*;
public class Main {
class stu{
String name;
int v;
void setname(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
String a[] = new String[105];
int b[] = new int[105];
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
int sm = 0;
for(int i = 1;i <= n; ++i) {
a[i] = cin.next();
int x = cin.nextInt();
int y = cin.nextInt();
int z = cin.nextInt();
b[i] = x * y * z;
sm += b[i];
}
String p1 = "",p2 = "";
int avg = sm / n;
for(int i = 1;i <= n; ++i) {
if(b[i] > avg) {
p1 = a[i];
}
else if(b[i] < avg){
p2 = a[i];
}
}
if(p1.equals("") && p2.equals("")) {
System.out.println("Case " + ca + ": no thief");
}
else System.out.println("Case " + ca + ": " + p1 + " took chocolate from " + p2);
}
cin.close();
}
}
B Hidden Secret!
题意:
给定两个字符串,问对这两个字符串进行如下操作后,其是否相同?
- 可以把一些大写字母改成小写,反之亦然。
- 可以自由添加/删除空格。
- 可以排列字母。
思路:
对字符串进行如下操作,然后进行判断。
- 删除字符串中的空格 。
- 所有字母都变为小写。
- 对字符串按字典序升序排序。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
char m1[] = new char[30];
char m2[] = new char[30];
cin.nextLine();
for(int ca = 1; ca <= t; ++ca){
for(int i = 0;i < 26; ++i) {
m1[i] = m2[i] = 0;
}
String s1 = cin.nextLine();
String s2 = cin.nextLine();
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
s1 = s1.replace(" ","");
s2 = s2.replace(" ","");
char t1[] = s1.toCharArray();
char t2[] = s2.toCharArray();
Arrays.sort(t1);
Arrays.sort(t2);
s1 = String.valueOf(t1);
s2 = String.valueOf(t2);
System.out.println("Case " + ca + ": " + (s1.equals(s2) ? "Yes" : "No"));
}
cin.close();
}
}
C Scarecrow
题意:
有 1 × N 1 \times N 1×N 的格子, . . . 是有作物的格子, # \# # 是没有作物格子,为了保护作物要在格子上放稻草人,每个稻草人可以保护它当前格和相邻格的作物。问至少需要多少个稻草人去保护作物?
思路:
用最少的稻草人去覆盖 . . . 的格子,每个稻草人可以连续覆盖三个格子,贪心考虑在 . . . 的格子上放稻草人一定不会比在 # \# # 的格子上放稻草人差。从前往后遍历格子,判断当前格子是不是 . . . ,如果是则往跳后三格。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
String tmp = cin.next();
char[] str = tmp.toCharArray();
int ans = 0;
for(int i = 0;i < n; ) {
if(str[i] == '.') {
ans++;
i += 3;
}
else {
++i;
}
}
System.out.println("Case " + ca + ": " + ans);
}
cin.close();
}
}
D Again Array Queries
题意:
给定 n n n 个数, q q q 次询问,每次给两个数 i , j i,j i,j ,问区间 [ i , j ] [i,j] [i,j] 任意两数的最小差值是多少?
思路:
考虑到 n n n 个数的范围为 [ 1 , 1000 ] [1,1000] [1,1000] ,根据鸽巢原理可知,如果 j − i + 1 > 1000 j - i + 1 > 1000 j−i+1>1000 ,最小差值为 0 0 0 ;否则,可以利用桶排序去暴力判断 [ i , j ] [i,j] [i,j] 的最小差值。
import java.util.*;
import java.math.*;
public class Main {
static int a[] = new int[100005];
static int b[] = new int[1005];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
int q = cin.nextInt();
for(int i = 0;i < n; ++i) {
a[i] = cin.nextInt();
}
System.out.println("Case " + ca + ": ");
int l, r;
while(q-- > 0) {
l = cin.nextInt();
r = cin.nextInt();
System.out.println(calc(l, r));
}
}
cin.close();
}
public static int calc(int l, int r) {
if(r - l + 1 >= 1000) {
return 0;
}
for(int i = 1;i <= 1000; ++i) {
b[i] = 0;
}
for(int i = l;i <= r; ++i) {
b[a[i]]++;
if(b[a[i]] > 1) return 0;
}
int mn = 1005, pre = 0;
for(int i = 1;i <= 1000; ++i) {
if(b[i] > 0) {
if(pre > 0) {
mn = Math.min(i - pre, mn);
pre = i;
}
else {
pre = i;
}
}
}
return mn;
}
}
E Scenes From a Memory
题意:
给定一个 k k k 位数,问可不可以删除一些位,让得到的数是一个非素数?
思路:
猜测这样的数不会超过 3 3 3 位,暴力判断 [ 1 , 3 ] [1,3] [1,3]位数。打表验证,这样的数不会超过 2 2 2 位。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
long a[] = new long[100005];
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
String s = cin.next();
calc(s, n);
}
cin.close();
}
public static boolean isPrime(int x) {
if(x == 1)return false;
for(int i = 2;i * i <= x; ++i) {
if(x % i == 0)return false;
}
return true;
}
public static void calc(String s, int n) {
for(int i = 0; i < s.length(); ++i) {
int now = (int)(s.charAt(i) - '0');
if(!isPrime(now)) {
System.out.println("1" + '\n' + now);
return ;
}
}
for(int i = 0;i < s.length(); ++i) {
for(int j = i + 1;j < s.length(); ++j) {
int now = (int)(s.charAt(i) - '0') * 10 + (int)(s.charAt(j) - '0');
if(!isPrime(now)) {
System.out.println("2" + '\n' + now);
return ;
}
}
}
for(int i = 0;i < s.length(); ++i) {
for(int j = i + 1;j < s.length(); ++j) {
for(int k = j + 1;k < s.length(); ++k) {
int now = (int)(s.charAt(i) - '0') * 100 + (int)(s.charAt(j) - '0') * 10 + (int)(s.charAt(k) - '0');
if(!isPrime(now)) {
System.out.println("3" + '\n' + now);
return ;
}
}
}
}
}
}
F Maximum Product
题意:
给定 n n n 个数,任意取 5 5 5 个数其乘积最大是多少?
思路:
把
0
0
0 剔除后按升序排序得到数组
a
[
1...
k
]
a[1...k]
a[1...k],如果少于
5
5
5 个数,直接输出
0
0
0 。
否则,取如下值的最大值:
- a [ k − 4 ] × a [ k − 3 ] × a [ k − 2 ] × a [ k − 1 ] × a [ k ] a[k-4] \times a[k-3] \times a[k-2] \times a[k-1] \times a[k] a[k−4]×a[k−3]×a[k−2]×a[k−1]×a[k]
- a [ 1 ] × a [ 2 ] × a [ k − 2 ] × a [ k − 1 ] × a [ k ] a[1] \times a[2] \times a[k-2] \times a[k-1] \times a[k] a[1]×a[2]×a[k−2]×a[k−1]×a[k]
- a [ 1 ] × a [ 2 ] × a [ 3 ] × a [ 4 ] × a [ k ] a[1] \times a[2] \times a[3] \times a[4] \times a[k] a[1]×a[2]×a[3]×a[4]×a[k]
import java.util.*;
import java.math.*;
public class Main {
static long a[] = new long[100005];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
for(int i = 1;i <= n; ++i) {
a[i] = cin.nextLong();
}
Arrays.sort(a, 1, n + 1);
System.out.println(calc(n));
}
cin.close();
}
public static long calc(int n) {
long ans = a[1] * a[2] * a[3] * a[4] * a[5];
for(int i = 1;i <= n - 4; ++i) {
ans = Math.max(ans, a[i] * a[i + 1] * a[i + 2] * a[i + 3] * a[i + 4]);
}
for(int i = 1;i <= n - 4; ++i) {
ans = Math.max(ans, a[i] * a[i + 1] * a[n - 2] * a[n - 1] * a[n]);
}
for(int i = 1;i <= n - 4; ++i) {
ans = Math.max(ans, a[i] * a[i + 1] * a[i + 2] * a[i + 3] * a[n]);
}
return ans;
}
}
G Sifid and Strange Subsequences
题意:
给定 a [ 1... n ] a[1...n] a[1...n] ,从中选出一些数 b [ 1... m ] b[1...m] b[1...m] , b [ i ] ∈ a [ 1... n ] b[i] \in a[1...n] b[i]∈a[1...n] ,满足对于任意的 i , j i,j i,j 有 ∣ b [ i ] − b [ j ] ∣ ≥ m a x ( b [ 1... n ] ) |b[i] - b[j]| \ge max(b[1...n]) ∣b[i]−b[j]∣≥max(b[1...n]) , 求 m m m 的最大值?
思路:
把 a [ 1... n ] a[1...n] a[1...n] 按升序排序后,贪心考虑先把负数和 0 0 0 取出来,然后求出 m i n ( ∣ b [ i ] − b [ j ] ∣ ) min(|b[i]-b[j]|) min(∣b[i]−b[j]∣) ,再取满足条件的正数,同时不断更新 m i n ( ∣ b [ i ] − b [ j ] ∣ ) min(|b[i]-b[j]|) min(∣b[i]−b[j]∣) 。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
long a[] = new long[100005];
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
for(int i = 1; i <= n; ++i) {
a[i] = cin.nextLong();
}
Arrays.sort(a, 1, n + 1);
int ans = 1, pos = n;
for(int i = 0;i < n; ++i) {
if(i + 1 > n || a[i + 1] > 0) {
pos = i;
break;
}
}
if(pos != 0) {
ans = pos;
long mn = 2000000000;
for(int i = 2;i <= pos; ++i) {
mn = Math.min(mn, a[i] - a[i - 1]);
}
// System.out.println("mn = " + mn);
long pre = a[pos];
for(int i = pos + 1;i <= n; ++i) {
mn = Math.min(mn, a[i] - pre);
pre = a[i];
if(a[i] <= mn) {
ans++;
}
else {
break;
}
}
}
System.out.println(ans);
}
cin.close();
}
}
H Nastia and Nearly Good Numbers
题意:
给定两个正整数 A , B A,B A,B ,问是否能找到三个不同的数 x , y , z x,y,z x,y,z ,使得 x + y = z x+y=z x+y=z ? x , y , z x,y,z x,y,z 满足以下条件:
- 如果一个整数能够整除 A × B A \times B A×B ,那么它是好的。
- 否则,如果一个整数能够整除 A A A ,那么它是几乎好的。
x , y , z x,y,z x,y,z 中要有一个数是好的,另外两个数是几乎好的。
思路:
- B = 1 B=1 B=1 ,无解。
- B = 2 B=2 B=2 , x = A , y = A × 3 , z = A × 4 x=A,y=A \times 3,z=A \times 4 x=A,y=A×3,z=A×4 。
- B > 2 B > 2 B>2 , x = A , y = A × ( B − 1 ) , z = A × B x=A,y=A \times (B-1),z=A \times B x=A,y=A×(B−1),z=A×B 。
import java.util.*;
import java.math.*;
public class Main {
class stu{
String name;
int v;
void setname(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
String a[] = new String[105];
int b[] = new int[105];
for(int ca = 1; ca <= t; ++ca){
long A = cin.nextLong();
long B = cin.nextLong();
if(B == 1) {
System.out.println("NO");
}
else if(B == 2) {
System.out.println("YES" + '\n' + A + ' ' + A * 3 + ' ' + A * 4);
}
else {
System.out.println("YES" + '\n' + A + ' ' + A * (B - 1) + ' ' + A * B);
}
}
cin.close();
}
}
I A-B Palindrome
题意:
给定一个由 0 , 1 , ? 0,1,? 0,1,? 构成的字符串和 a a a 个 0 0 0 , b b b 个 1 1 1 ,你可以在 ? ? ? 的位置填 0 , 1 0,1 0,1 ,问使得填完之后的字符串是否是回文串。
思路:
- 判断给定的字符串是否回文,即 0 0 0 对 0 0 0 , 1 1 1 对 1 1 1 。
- 根据回文的性质暴力填 0 , 1 0,1 0,1 ,与 0 0 0 对应的 ? ? ? 填 0 0 0 ,与 1 1 1 对应的 ? ? ? 填 1 1 1 。填完之后看 0 , 1 0,1 0,1 是否用超了。
- 最后再把 ? ? ? 对应 ? ? ? 的位置填完。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
char s[] = new char[400005];
for(int ca = 1; ca <= t; ++ca){
int na = cin.nextInt();
int nb = cin.nextInt();
cin.nextLine();
String str = cin.nextLine();
s = str.toCharArray();
int flag = 0;
for(int i = 0, j = s.length - 1; i <= j; ++i, --j) {
if(s[i] != '?') {
if(s[j] == '?')s[j] = s[i];
else if(s[i] != s[j]){
flag = 1;
break;
}
}
else if(s[j] != '?') {
if(s[i] == '?')s[i] = s[j];
}
}
if(flag == 1) {
System.out.println("-1");
continue;
}
int nowa = 0, nowb = 0;
for(int i = 0;i < s.length; ++i) {
if(s[i] == '0')nowa++;
else if(s[i] == '1')nowb++;
}
if(nowa > na || nowb > nb) {
System.out.println("-1");
continue;
}
nowa = na - nowa;
nowb = nb - nowb;
for(int i = 0, j = s.length - 1; i <= j; ++i, --j) {
if(s[i] == '?') {
if(i != j) {
if(nowa > 1) {
s[i] = s[j] = '0';
nowa -= 2;
}
else if(nowb > 1) {
s[i] = s[j] = '1';
nowb -= 2;
}
}
else if(i == j) {
if(nowa > 0) {
s[i] = '0';
nowa--;
}
else if(nowb > 0) {
s[i] = '1';
nowb--;
}
}
}
}
if(nowa == 0 && nowb == 0) {
for(int i = 0; i < s.length; ++i) {
System.out.print(s[i]);
}
System.out.println("");
}
else {
System.out.println("-1");
}
}
cin.close();
}
}
J Repainting Street
题意:
有 n n n 个有颜色的房子,第 i i i 个房子的颜色为 c i c_i ci 。Tom每天可以把连续 k k k 个房子涂成同一种颜色,问最少多少天可以把所有房子涂成同一种颜色?
思路:
c i ∈ [ 1 , 100 ] c_i \in [1,100] ci∈[1,100] ,可以暴力把所有房子涂成100种颜色分别需要多少时间算出来,然后取最小值。(该题跟C稻草人那题差不多,模改一下代码即可)
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
int c[] = new int[100010];
for(int ca = 1; ca <= t; ++ca){
int n = cin.nextInt();
int k = cin.nextInt();
for(int i = 1;i <= n; ++i) {
c[i] = cin.nextInt();
}
int ans = n;
for(int color = 1; color <= 100; ++color) {
int now = 0;
for(int i = 1;i <= n; ) {
if(c[i] != color) {
i += k;
now++;
}
else {
i++;
}
}
if(now < ans)ans = now;
}
System.out.println(ans);
}
cin.close();
}
}