填空题:只需要算出结果后提交即可;结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
编程题:要求写出完整代码并符合题干中时间内存限制。
本题总分:5 分
【问题描述】
已知今天是星期六,请问20的22天后是星期几?注意用数字 1 到 7 表示星期一到星期日。
// Kim:
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int star = 6;
int m = 0;
int n = 20;
for(int i=1;i<=22;i++){
m = n%7;
n = n*m;
}
int res = (star+m)%7;
res = (res==0?7:res);
System.out.println(res);
scan.close();
}
}
// 结果:测试通过
// 注意:星期一到星期六可以通过取余得到,星期天要特殊处理
本题总分:5 分
【问题描述】
这天小明正在学数数。他突然发现有些正整数的形状像一座“山”,比如 123565321、145541,它们左右对称(回文)且数位上的数字先单调不减,后单调不增。
小明数了很久也没有数完,他想让你告诉他在区间 [2022, 2022222022] 中有多少个数的形状像一座“山”。
// Kim:
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int count = 0;
for(int i=2022;i<=2022022;i++){
if(isHui(i) && isUp(i)){
count++;
}
}
System.out.println(count);
scan.close();
}
public static boolean isHui(int num){
String str1 = String.valueOf(num);
// System.out.println(str1);
StringBuffer stf = new StringBuffer(str1);
// System.out.println(stf);
String str2 = stf.reverse().toString();
// System.out.println(str2);
if(str1.equals(str2)){
return true;
}
return false;
}
public static boolean isUp(int num){
char []chars = String.valueOf(num).toCharArray();
int len = chars.length/2;
// System.out.println(len);
for(int i=1;i<=len;i++){
if(chars[i]<chars[i-1]){
return false;
}
}
return true;
}
}
// 结果:官网内运行超时、idea中内存溢出错误;基本思路和正确的代码一致、在数据量少的情况运行正确;不知道是不是在String、StringBuffer和char数组之间转换的时候浪费了太多的时间,比参考代码运行时间长一点
// 巩固:int转String方法:valueOf(str)、StringBuffer转String方法:toString()、StringBuffer倒置方法:reverse()、String转char数组方法:toCharArray()
// 参考的正确代码在官网内也运行超时、但在idea中可以显示正确结果;代码如下:
// *
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int sum = 0;
for(int i=2022;i<=2022222022;i++) {
if(isUp(i)&&isMirror(i)) {
sum++;
}
}
System.out.println(sum);
}
public static boolean isMirror(int num){
StringBuffer str = new StringBuffer(num+"");
if((str.toString()).equals(str.reverse().toString()))
return true;
return false;
}
public static boolean isUp(int num){
String st=num+"";
int len=st.length()%2==0?st.length()/2:st.length()/2+1;
for(int i=1;i<len;i++) {
if(st.charAt(i)<st.charAt(i-1)) {
return false;
}
}
return true;
}
}
// 学习:int转换为String的快速方法:num+“”
// 最后找的正确代码如下:
public class Main{
//[2022,2022222022]
static int cnt=0,cnt2=0;
public static void main(String[] args) {
for (int i =10; i <=20222; i++) {
if(check(i)) {
if(i>=22) {
cnt++;
}
}
}
System.out.println(cnt+cnt2);
}
public static boolean check(int i) {
String tmp=String.valueOf(i);
int index=tmp.length()-1;
while(index>=1) {
int j=Integer.valueOf(String.valueOf(tmp.charAt(index)));
int k=Integer.valueOf(String.valueOf(tmp.charAt(index-1)));
if(j<k) return false;
index--;
}
if(tmp.length()<5) {
int diff=10-Integer.valueOf(String.valueOf(tmp.charAt(tmp.length()-1)));
cnt2+=diff;
}
return true;
}
}
// 没看明白循环和cnt2计数的操作
最后决定在给定环境中利用代码*分成多段进行操作并将结果相加得出最终结果
时间限制: 1.0s 内存限制: 512.0MB 本题总分:10 分
【问题描述】
给定一个只包含大写字母的字符串 S ,请你输出其中出现次数最多的字母。如果有多个字 母均出现了最多次,按字母表顺序依次输出所有这些字母。
【输入格式】
一个只包含大写字母的字符串 S .
【输出格式】
若干个大写字母,代表答案。
【样例输入】
BABBACAC
【样例输出】
AB
【评测用例规模与约定】
对于 100% 的评测用例,1 ≤ |S | ≤ 10^{6}.
// Kim:
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
String str = scan.next();
char []chars = str.toCharArray();
int len = str.length();
int []count = new int[26];
for(int i=0;i<len;i++){
int loc = (char)(chars[i])-65;
count[loc]++;
}
int max = 0;
int []maxloc = new int[26];
int maxcnt = 0;
for(int i=0;i<26;i++){
if(count[i]>max){
max = count[i];
}
}
for(int i=0;i<26;i++){
if(count[i]==max){
char res = (char)(i+65);
System.out.print(res);
}
}
scan.close();
}
}
// 结果:测试通过
// 积累:借助下标来实现计数
时间限制: 1.0s 内存限制: 512.0MB 本题总分:10 分
【问题描述】
小蓝老师教的编程课有 N 名学生,编号依次是 1 . . . N。第 i 号学生这学期刷题的数量是 A_{i}。
对于每一名学生,请你计算他至少还要再刷多少道题,才能使得全班刷题比他多的学生数不 超过刷题比他少的学生数。
【输入格式】
第一行包含一个正整数 N。
第二行包含 N 个整数:A_{1},A_{2},A_{3} ,. . . , A_{N}.
【输出格式】
输出 N 个整数,依次表示第 1 . . . N 号学生分别至少还要再刷多少道题。
【样例输入】
5
12 10 15 20 6
【样例输出】
0 3 0 0 7
【评测用例规模与约定】
对于 30% 的数据,1 ≤ N ≤ 1000, 0 ≤ A_{i} ≤ 1000.
对于 100% 的数据,1 ≤ N ≤ 100000, 0 ≤ A_{i} ≤ 100000.
// Kim:
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int n = scan.nextInt();
int []a = new int[n];
int []t = new int[n];
for(int i=0;i<n;i++){
a[i] = scan.nextInt();
t[i] = a[i];
}
Arrays.sort(t);
int midloc = n/2;
int mid = t[midloc];
int fmid = t[(midloc-1)];
int []res = new int[n];
for(int i=0;i<n;i++){
if(a[i]==mid){
if(a[i]==fmid){
res[i] = 1;
}else{
res[i] = 0;
}
}
if(a[i]>mid){
res[i] = 0;
}
if(a[i]<mid){
if(n%2==0){
res[i] = mid-a[i];
}else{
res[i] = mid-a[i]+1;
}
}
}
for(int i=0;i<n;i++){
System.out.print(res[i]);
System.out.print(" ");
}
scan.close();
}
}
// 陷入的盲区:每次拿出一个,数量上不会有太大变化,也就是说可实现每次和中位数比较即可
// 测试结果:5/10 错误1eg:0 0 1 1 1 1 1 2 2 2 10->要保证此时坐标和midloc不同
// 在调试好错误1后,调试无问题,但提交检测有问题
时间限制: 1.0s 内存限制: 512.0MB
本题总分:15 分
【问题描述】
满足 N! 的末尾恰好有 K 个 0 的最小的 N 是多少?
如果这样的 N 不存在输出 −1。
【输入格式】
一个整数 K。
【输出格式】
一个整数代表答案。
【样例输入】
2
【样例输出】
10
【评测用例规模与约定】
对于 30% 的数据,1 ≤ K ≤ 10^{6}.
对于 100% 的数据,1 ≤ K ≤ 10^{18}.
// Kim:
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int k = scan.nextInt();
double temp = Math.pow(10, k);
k = (int)temp;
int k1 = k*10;
long cul = 1;
for(long i=2;i<=5;i++){
cul = cul*i;
}
long count = 6;
while(count<=k){
if(cul%k==0 && cul%k1!=0){
System.out.println(count-1);
return;
}
cul = cul*count;
count++;
}
System.out.println(-1);
scan.close();
}
}
// 第一时间想到的暴力法:只通过1个测试用例,其余均出现段错误及运行超时
// 尝试二分类去解决:没想出来
最后找的正确代码如下:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 末位0的个数
long k = scanner.nextLong();
long lef = 1;
long rig = (long)9e18;
// 找符合条件的最小值
// 采用二分查找法
while(lef < rig) {
long mid = (lef + rig)/2;
if(k <= num_of_zero(mid)) {
rig = mid;
}
else {
lef = mid + 1;
}
}
// while最终停止情况如下两种:
// 一是当rig恰好取得结果值即k=num_of_zero(mid)【即找到】,在下一次循环时进入else,lef=rig+1,即lef>rig跳出循环;
// 二是当k>num_of_zero(mid)【即未找到】,在下一次循环时进入else,lef=rig+1,即lef>rig跳出循环
if(num_of_zero(lef) == k)
System.out.println(rig);
else {
System.out.println(-1);
}
scanner.close();
}
// 判断一个数的阶乘的末尾有几个0
private static Long num_of_zero(long tmp) {
// cnt标记0的个数
long cnt = 0;
while(tmp > 0) {
cnt += tmp / 5;
tmp /= 5;
}
return cnt;
}
}
学习:num_of_zero()判断一个数的阶乘的末尾有几个0方法:能产生0的质数组合只有2 * 5,然后问题就转变成了对N!质数分解后,一共有几个5,因为2的个数显然多于5【偶数均可以分解出2】。比如计算25!的末尾0的个数,包含5的数有5,10,15,20,25,其中25中包含两个5【25=5*5】,所以一共包含6个5,25!的末尾有6个0
时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 15 分
【问题描述】
小明有一个大小为 N × M 的矩阵,可以理解为一个 N 行 M 列的二维数组。
我们定义一个矩阵 m 的稳定度 f ( m ) 为 f ( m ) = max ( m ) − min ( m ) ,其中 max ( m )
表示矩阵 m 中的最大值, min ( m ) 表示矩阵 m 中的最小值。现在小明想要从这
个矩阵中找到一个稳定度不大于 limit 的子矩阵,同时他还希望这个子矩阵的面
积越大越好(面积可以理解为矩阵中元素个数)。
子矩阵定义如下:从原矩阵中选择一组连续的行和一组连续的列,这些行
列交点上的元素组成的矩阵即为一个子矩阵。
【输入格式】
第一行输入两个整数 N , M ,表示矩阵的大小。
接下来 N 行,每行输入 M 个整数,表示这个矩阵。
最后一行输入一个整数 limit ,表示限制。
【输出格式】
输出一个整数,分别表示小明选择的子矩阵的最大面积。
【样例输入】
3 4
2 0 7 9
0 6 9 7
8 4 6 4
8
【样例输出】
6
【样例说明】
满足稳定度不大于 8 的且面积最大的子矩阵总共有三个,他们的面积都是
6 (粗体表示子矩阵元素):
2 0 7 9
0 6 9 7
8 4 6 4
2 0 7 9
0 6 9 7
8 4 6 4
2 0 7 9
0 6 9 7
8 4 6 4
【评测用例规模与约定】
评测用例编号 N M
1, 2 1 ≤ N ≤ 10 1 ≤ M ≤ 10
3, 4 N = 1 M ≤ 100000
5 ∼ 12 1 ≤ N ≤ 10 M ≤ 10000
13 ∼ 20 1 ≤ N ≤ 80 1 ≤ M ≤ 80
对于所有评测用例, 0 ≤ 矩阵元素值 , limit ≤ 10^{5} 。
思路:二维矩阵比较大小的时候转换为一维矩阵去比较
import java.io.*;
import java.util.*;
public class Main {
// max[k][i][j]表示第k列中[i,j]之间的最大值->(1)
// 将每一段矩阵高的最大值和最小值存储下来并保证寻找limit内最大
static int[][][] max;
static int[][][] min;
static int n, m, limit,ans;
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
String[] s=br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
// 坐标:列 行 行
max=new int[m+1][n+1][n+1];
min=new int[m+1][n+1][n+1];
// 矩阵赋值
for (int i = 1; i <= n; i++) {
s=br.readLine().split(" ");
for (int j = 1; j <= m; j++) {
max[j][i][i] = min[j][i][i] = Integer.parseInt(s[j-1]);
}
}
// 表示最大限制
limit = Integer.parseInt(br.readLine());
//预处理 复杂度 n^2*m
// 这里的i和j表示的是行的范围,即[k][j][j]表示的就是某行某列的元素
// 记录列中每一段范围的最大值和最小值
for (int k = 1; k <= m; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
max[k][i][j] = Math.max(max[k][i][j - 1], max[k][j][j]);
min[k][i][j] = Math.min(min[k][i][j - 1], min[k][j][j]);
}
}
}
for (int x1 = 1; x1 <= n; x1++) {
for (int x2 = x1; x2 <= n; x2++) {
int l = 1, r = m;
while (l < r) {
// >>右移运算符 右移一位相当于除以2
int mid = l + r + 1 >> 1;
if (check(x1, x2, mid)) l = mid;
else r = mid - 1;
}
if (check(x1,x2,r)) ans=Math.max(ans,(x2-x1+1)*r);
}
}
out.println(ans);
out.flush();
}
//k是窗口大小
static boolean check(int x1, int x2, int k) {
// Deque表示双端队列,双端队列是在两端都可以进行插入和删除的队列
Deque<Integer> qmax = new ArrayDeque<>();
Deque<Integer> qmin = new ArrayDeque<>();
for (int i = 1; i <= m; i++) {
// peekLast()返回双端队列最后一个元素,若元素为空,则返回null
// pollLast()此方法检索并删除此双端队列的最后一个元素,如果此双端队列为空,则返回null
while (!qmin.isEmpty() && min[qmin.peekLast()][x1][x2] > min[i][x1][x2]) qmin.pollLast();
// offerLast(E e)方法会将指定的元素插入Deque的末尾
qmin.offerLast(i);
//处理最大
// peekFirst() 方法检索而不是删除给定双端队列的第一个元素
// pollFirst() 此方法检索并删除此双端队列的第一个元素,如果此双端队列为空,则返回null
if (!qmax.isEmpty() && qmax.peekFirst() < i - k + 1) qmax.pollFirst();
while (!qmax.isEmpty() && max[qmax.peekLast()][x1][x2] < max[i][x1][x2]) qmax.pollLast();
// offerLast(E e)方法会将指定的元素插入Deque的末尾
qmax.offerLast(i);
//说明窗口为k
if (i >= k && max[qmax.peekFirst()][x1][x2] - min[qmin.peekFirst()][x1][x2] <= limit) return true;
}
return false;
}
}
题解:https://blog.51cto.com/u_15492302/5729136#3Ac_code_47
(1)确定x边界【即在数组中记录列(矩阵高)每一范围的最大值及最小值】-二维处理为一维
(2)确定y边界【即确定矩阵宽】-二分
(3)定义全局变量计算面积,更新答案