目录
201312-2:ISBN号码
201403-2:窗口
201409-2:画图
201412-2:Z字型扫描
201503-2:数字排序
201509-2:日期计算
201512-2:消除类游戏
201604-2:俄罗斯方块
201609-2:火车购票
201612-2:工资计算
201703-2:学生排队
201709-2:公共钥匙盒
201712-2:游戏
201803-2:碰撞的小球
201809-2:买菜
201812-2:小明放学
201903-2:二十四点
思路:
1.这题主要考察字符串中的单个字符处理
2.判断非‘-’号时的数字递进乘积即可
3.Char中的数字字符与int数字转换:减去字符‘0’即可
4.注意输出时接的为String的“X”(双引号),而不是Char的‘X’(单引号)
import java.util.Scanner;
public class CSP201312_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String ISBN = sc.next();
int sum = 0;
for(int i = 0, j = 1; i < 11; i++) {
if(ISBN.charAt(i) != '-') {
sum += (ISBN.charAt(i) - '0') * j;
j++;
}
}
int idCode = sum % 11;
if((idCode == 10 && ISBN.charAt(12) == 'X') || idCode == ISBN.charAt(12) - '0') {
System.out.println("Right");
}else {
System.out.println(ISBN.substring(0, 12) + (idCode == 10 ? "X" : idCode)); //注意输出时接的为String的“X”(双引号),而不是Char的‘X’(单引号)
}
}
}
思路:
1.采用链表方便删除中间结点并添加该结点到最后(移动被点击窗口到最前面)
2.点击时注意点击到窗口边界上情况
import java.util.Scanner;
import java.util.LinkedList;
class Window {
int id = 0;
int x1 = 0;
int y1 = 0;
int x2 = 0;
int y2 = 0;
}
public class CSP201403_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
LinkedList wl = new LinkedList();
int[][] click = new int[m][2];
for(int i = 1; i <= n; i++) {
Window w = new Window();
w.id = i;
w.x1 = sc.nextInt();
w.y1 = sc.nextInt();
w.x2 = sc.nextInt();
w.y2 = sc.nextInt();
wl.add(w);
}
for(int i = 0; i < m; i++) {
for(int j = 0; j < 2; j++) {
click[i][j] = sc.nextInt();
}
}
Window temp = new Window();
for(int i = 0; i < m; i++) {
int flag = 0;
for(int j = n - 1; j >= 0; j--) {
if(click[i][0] >= wl.get(j).x1 && click[i][0] <= wl.get(j).x2 && click[i][1] >= wl.get(j).y1 && click[i][1] <= wl.get(j).y2) {
System.out.println(wl.get(j).id);
temp = wl.get(j);
wl.remove(j);
wl.addLast(temp);
flag = 1;
break;
}
}
if(flag == 0) {
System.out.println("IGNORED");
}
}
}
}
思路:
1.建立二维数组作为整个坐标系,数组中的值默认为0,0代表没涂色,1代表已涂色
2.输入的左下角的坐标作为循环的起点,右上角的坐标作为循环的终点
3.每次循环时,检查位置是否已经涂色,若位置状态为0,则将位置状态设置为1,计数器加1(代表涂色面积加1),最后输出计数器的值即为涂色的面积。
import java.util.Scanner;
public class CSP201409_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] coordinate = new int[101][101];
int n = sc.nextInt();
int[][] rectangle = new int[n][4];
int sum = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < 4; j++) {
rectangle[i][j] = sc.nextInt();
}
for(int x = rectangle[i][0]; x < rectangle[i][2]; x++) {
for(int y = rectangle[i][1]; y < rectangle[i][3]; y++) {
if(coordinate[x][y] == 0) {
coordinate[x][y] = 1;
sum++;
}
}
}
}
System.out.println(sum);
}
}
方法一思路:
1.采用两个代表横纵坐标的双指针来控制坐标位置
2.观察到扫描方向有四种:右→、左下↙、下↓、右上↗
3.观察到方向转换有10种:右-左下、右-右上;
左下-下、左下-左下、左下-右;
下-右上、下-左下;
右上-右上、右上-右、右上-下;
4.根据观察,分为四种情况来改变坐标指针,每种情况又根据自身方向转换情况调整下一次的方向
import java.util.Scanner;
public class CSP201412_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] rectangle = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
rectangle[i][j] = sc.nextInt();
}
}
int row = 0;
int col = 0;
String direction = "right";
while(row >= 0 && row < n && col >= 0 && col < n) {
System.out.print(rectangle[row][col] + " ");
switch (direction) {
case "right":
col++;
if(row == 0) {
direction = "leftDown";
}else {
direction = "rightUp";
}
break;
case "leftDown":
row++;
col--;
if(col == 0 && row != n-1) {
direction = "down";
}else if(row == n-1) {
direction = "right";
}else {
direction = "leftDown";
}
break;
case "down":
row++;
if(col == 0) {
direction = "rightUp";
}else {
direction = "leftDown";
}
break;
case "rightUp":
row--;
col++;
if(row == 0 && col != n-1) {
direction = "right";
}else if(col == n-1) {
direction = "down";
}else {
direction = "rightUp";
}
break;
}
}
}
}
方法二思路:
1.采用两个代表横纵坐标的双指针来控制坐标位置
2.每个对角线上的横纵坐标索引和恒为一个常数,用一个对角线行数索引表示
3.每次走一个对角线,偶数索引对角线移动方向为右上,每次移动行-1,列+1;奇数索引对角线移动方向为左下,每次移动行+1,列-1
4.每次变线时对角线索引始终不能超过n-1,在上半部分时为索引本身,在下半部分为n-1
import java.util.Scanner;
public class CSP201412_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] rectangle = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
rectangle[i][j] = sc.nextInt();
}
}
int row = 0;
int col = 0;
int diagonal = row + col; //对角线行数索引:对角线上的行索引加列索引的和恒为一个常数,可理解为对角线行数的索引
while(diagonal < 2*n-1) {
if(diagonal % 2 == 0) {
row = diagonal > n-1 ? n-1 : diagonal; //每次变线时对角线索引始终不能超过n-1,在上半部分时为索引本身,在下半部分为n-1
col = diagonal - row;
for (; col <= diagonal && col < n; col++, row--) //偶数索引对角线移动方向为右上,每次移动行-1,列+1
{
System.out.print(rectangle[row][col] + " ");
}
}
else {
col = diagonal > n - 1 ? n - 1 : diagonal;
row = diagonal - col;
for (; row <= diagonal && row < n; row++, col--) //奇数索引对角线移动方向为左下,每次移动行+1,列-1
{
System.out.print(rectangle[row][col] + " ");
}
}
diagonal++;
}
}
}
思路:
1.用一个数组存储输入的数的次数,索引为输入的数
2.遍历数组,找出数组里的最大值,输出索引和次数,然后将该索引的次数置为0,当最大值为0时,终止循环。
import java.util.Scanner;
public class CSP201503_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] sum = new int[1001];
for(int i = 0; i < n; i++) {
sum[sc.nextInt()]++;
}
int max = -1;
while(max != 0) {
max = 0;
int index = -1;
for(int j = 0; j < 1001; j++) {
if(sum[j] > max) {
max = sum[j];
index = j;
}
}
if(index != -1) {
System.out.println(index + " " + max);
sum[index] = 0;
}
}
}
}
思路:
1.先判断是闰年还是平年,然后创建相应的月份数组
2.然后一个月一个月地进行判断和推进
import java.util.Scanner;
public class CSP201509_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int year = sc.nextInt();
int days = sc.nextInt();
int[] months = new int[]{31,28,31,30,31,30,31,31,30,31,30,31};
if(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
months[1] = 29;
}
int month = 1;
int day = 0;
int i = 0;
while(days > 0) {
if(days > months[i]) {
month++;
}else{
day = days;
}
days -= months[i];
i++;
}
System.out.println(month);
System.out.println(day);
}
}
思路:
1.用一个二维数组存放输入的矩阵,用另一个二维数组存放消除后的矩阵
2.行列分别进行消除,遍历数组,当有三个连续相同的数则全置为0
import java.util.Scanner;
public class CSP201512_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] input = new int[n][m];
int[][] out = new int[n][m];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
input[i][j] = sc.nextInt();
out[i][j] = input[i][j];
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
//行消除
if(j
思路:
0.根据题目可知,所有0的位置不用考虑,且仅考虑方块下落的四列即可
1.找出方块下落所移动的距离,即方块所有列单独可移动的最短距离
2.找出方块中每一列的最下面一个1的位置,即该列的上界
3.找出方格图中每一列最上面一个1的位置,即该列的下界
4.下界减去上界为两个1之间的距离,该距离再减去1即该列的方块可以移动的距离,计算每列的移动距离后找出最短的移动距离,即方块下落所能移动的距离
5.将方块中为1的数移动上面所求最小距离后填入方格图中
import java.util.Scanner;
public class CSP201604_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] rectangle = new int[15][10];
int[][] patch = new int[4][4];
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 10; j++) {
rectangle[i][j] = sc.nextInt();
}
}
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
patch[i][j] = sc.nextInt();
}
}
int location = sc.nextInt();
location--;
//找出方块下落所移动的距离,即方块所有列单独可移动的最短距离
int minDistance = 16;
for(int column = 0; column < 4; column++) {
//找该列的上界
int upEdge = -1;
for(int row = 0; row < 4; row++) {
if(patch[row][column] == 1) {
upEdge = row;
}
}
if(upEdge == -1) {
continue;
}
//找该列的下界
int downEdge = 15;
for(int row = 14; row > 3; row--) {
if(rectangle[row][column + location] == 1) {
downEdge = row;
}
}
minDistance = downEdge-upEdge < minDistance ? downEdge-upEdge : minDistance;
}
//移动方块
for(int row = 0; row < 4; row++) {
for(int column = 0; column < 4; column++) {
if(patch[row][column] == 1) {
rectangle[row + (minDistance-1)][column +location] = 1;
}
}
}
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 10; j++) {
System.out.print(rectangle[i][j] + " ");
}
System.out.println();
}
}
}
方法一思路:
1.座位没卖出前标记为0,卖出后标记为1
2.先按连续座位需求检索,检索每一排是否有可满足的连续座位,有则分配
3.若全部检索完没有满足连续的座位,则插空安排座位,但凡座位为0就给分配
4.判断每一排连续座位时采用正向双指针,逐行检测是否满足当前连续购票需求
import java.util.Scanner;
public class CSP201609_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arrN = new int[n];
int[][] location = new int[20][5];
for(int i = 0; i < n; i++) {
arrN[i] = sc.nextInt();
int buyFlag = 0;
for(int row = 0; row < 20; row++) {
int pointOne = 0;
int pointTwo = 0;
while(pointTwo < 5) {
int conSpace = 0;
while(pointOne < 5 && location[row][pointOne] != 0) {
pointOne++;
}
pointTwo = pointOne;
while(pointTwo < 5 && location[row][pointTwo] == 0) {
conSpace++;
pointTwo++;
}
if(conSpace >= arrN[i]) {
for(int buyTicket = 0; buyTicket < arrN[i]; buyTicket++) {
location[row][pointOne] = 1;
System.out.print((row*5+pointOne+1)+" ");
pointOne++;
}
buyFlag = 1;
break;
}
pointOne = pointTwo;
}
if(buyFlag == 1) {
break;
}
}
if(buyFlag == 0) {
int buyTicket = 0;
for(int row = 0; row < 20; row++) {
for(int column = 0; column < 5; column++) {
while(location[row][column]==0 && buyTicket
方法二思路:
1.采用LinkedList实现队列,每个队列里的值存储每个位置的号
2.因为每一行总是从第一个空位开始往后安排,所以每次安排时将队列中的顶部的值返回后将其删除即可
import java.util.Scanner;
import java.util.LinkedList;
public class CSP201609_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arrN = new int[n];
LinkedList[] queue = new LinkedList[20];
for(int i = 0; i < queue.length; i++) {
queue[i] = new LinkedList();
for(int j = 0; j < 5; j++) {
queue[i].add(i*5+j+1); //存储的值为每个位置的号
}
}
for(int i = 0; i < n; i++) {
arrN[i] = sc.nextInt();
int buyFlag = 0;
for(int row = 0; row < queue.length; row++) {
if(queue[row].size() >= arrN[i]) {
for(int buyTicket = 0; buyTicket < arrN[i]; buyTicket++) {
System.out.print(queue[row].pop() + " ");
}
buyFlag = 1;
break;
}
}
if(buyFlag == 0) {
int buyTicket = 0;
for(int row = 0; row < queue.length; row++) {
while(queue[row].size() != 0 && buyTicket < arrN[i]) {
System.out.print(queue[row].pop() + " ");
buyTicket++;
}
if(buyTicket == arrN[i]) {
break;
}
}
}
System.out.println();
}
}
}
方法一思路:(正向求解:根据税前求税后)
1.先判断税后收入是否大于3500,不大于则税前收入等于税后收入,大于则计算需要缴多少税
2.根据题意税前工资为一个整百的数,所以根据税后工资依次加一百计算缴纳的税,当税前工资-缴纳的税=税后工资时,输出税前工资
import java.util.Scanner;
public class CSP201612_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
if(T <= 3500) {
System.out.println(T);
}else {
int S = T/100*100;
while(true) {
S += 100;
int tax = 0;
int A = S - 3500;
if(A <= 1500) {
tax += A/100*3;
}else if(A <= 4500) {
tax += 1500/100*3;
tax += (A-1500)/10;
}else if(A <= 9000) {
tax += 1500/100*3;
tax += (4500-1500)/10;
tax += (A-4500)/5;
}else if(A <= 35000) {
tax += 1500/100*3;
tax += (4500-1500)/10;
tax += (9000-4500)/5;
tax += (A-9000)/4;
}else if(A <= 55000) {
tax += 1500/100*3;
tax += (4500-1500)/10;
tax += (9000-4500)/5;
tax += (35000-9000)/4;
tax += (A-35000)/10*3;
}else if(A <= 80000) {
tax += 1500/100*3;
tax += (4500-1500)/10;
tax += (9000-4500)/5;
tax += (35000-9000)/4;
tax += (55000-35000)/10*3;
tax += (A-55000)/100*35;
}else {
tax += 1500/100*3;
tax += (4500-1500)/10;
tax += (9000-4500)/5;
tax += (35000-9000)/4;
tax += (55000-35000)/10*3;
tax += (80000-55000)/100*35;
tax += (A-80000)/100*45;
}
if((S-tax) == T) {
System.out.println(S);
break;
}
}
}
}
}
方法二思路:(反向求解:根据税后求税前)
1.根据每个税率范围的端点先计算真实税后收入的范围
2.判断输入的税后收入处于哪个范围
3.根据税后收入反推不交税前的税前收入(除以(1-税率))
备注:从编程方法上来说,一种是将工资段和税率写到程序逻辑中。这种做法修改程序比较难,逻辑也比较复杂。另外一种是查表法,通过查表来计算最后的结果。查表法的优点在于,单有关规定改变时,只需要调整表格,而不需要改变程序逻辑。难点在于比赛时不够直观,所以根据情况自行选择。该问题原始数据可以建两个表格,一是工资收入段表,二是税率表。根据这两个表可以算出收入范围表,即由实际收入得到最高税率是哪一档的表。进一步的计算就变得简单许多。
import java.util.Scanner;
public class CSP201612_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
int[] salary = new int[]{3500, 3500+1500, 3500+4500, 3500+9000, 3500+35000, 3500+55000, 3500+80000};
int[] taxRate= new int[]{3, 10, 20, 25, 30, 35, 45};
int[] salaryAfterTax = new int[salary.length]; //税后收入
salaryAfterTax[0] = salary[0];
//计算税后收入范围
for(int i = 1; i < salaryAfterTax.length; i++) {
salaryAfterTax[i] = salaryAfterTax[i-1] + (salary[i] - salary[i-1]) - (salary[i] - salary[i-1])*taxRate[i-1]/100;
}
//判断输入的税后收入处于哪个范围
int i = 0;
for(i = 0; i < salaryAfterTax.length; i++) {
if(T <= salaryAfterTax[i]) {
break;
}
}
int S = 0;
if(i == 0) {
S = T;
}else{
S = salary[i-1] + (T - salaryAfterTax[i-1])*100/(100-taxRate[i-1]);
}
System.out.println(S);
}
}
思路:
1.采用LinkedList存储学生学号,然后按要求删除结点和插入结点即可
import java.util.Scanner;
import java.util.LinkedList;
public class CSP201703_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
LinkedList studentId = new LinkedList();
for(int i = 0; i < n; i++) {
studentId.add(i+1);
}
int m = sc.nextInt();
int[][] action = new int[m][2];
for(int i = 0; i < m; i++) {
for(int j = 0; j < 2; j++) {
action[i][j] = sc.nextInt();
}
int index = studentId.indexOf(action[i][0]);
studentId.remove(index);
studentId.add(index + action[i][1], action[i][0]);
}
for(int i = 0; i < n; i++) {
System.out.print(studentId.get(i) + " ");
}
}
}
思路:
1.以时间为循环条件,每一个时间点判断一次是否有归还钥匙或取钥匙
2.计算取钥匙的最小时间和归还钥匙的最晚时间,作为循环的起点和终点
3.同一时间点必须先归还,后取
4.归还时注意多人同时归还情况,需按钥匙编号从小到大归还,所以声明一个数组来存储多人同时归还时的钥匙编号,便于排序
5.取时随意取,不用按顺序
import java.util.Scanner;
import java.util.Arrays;
public class CSP201709_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] key = new int[n];
for(int i = 0; i < n; i++) {
key[i] = i+1;
}
int k = sc.nextInt();
int[][] action = new int[k][4];
for(int i = 0; i < k; i++) {
for(int j = 0; j < 3; j++) {
action[i][j] = sc.nextInt();
}
action[i][3] = action[i][1]+action[i][2]; //第四位存储上完课后的时间点
}
int minTime = 10001; //起始时间
int maxTime = 0; //终止时间
for(int i = 0; i < k; i++) {
minTime = action[i][1] < minTime ? action[i][1] : minTime;
maxTime = action[i][3] > maxTime ? action[i][3] : maxTime;
}
for(int time = minTime; time <= maxTime; time++) { //以时间点为循环,每一个时间点判断一次是否有还钥匙和取钥匙
//还钥匙
int many = 0; //存储有几个人还钥匙
for(int i = 0; i < k; i++) {
if(action[i][3] == time) {
many++;
}
}
if(many != 0) {
int[] returnKeys = new int[many];
for(int i = 0; i < k; i++) {
if(action[i][3] == time && many!=0) {
returnKeys[many-1] = action[i][0];
many--;
}
}
Arrays.sort(returnKeys);
for(int i = 0; i < returnKeys.length; i++) {
for(int j = 0; j < n; j++) {
if(key[j] == 0) {
key[j] = returnKeys[i];
break;
}
}
}
}
//取钥匙
for(int i = 0; i < k; i++) {
if(action[i][1] == time) {
for(int j = 0; j < n; j++) {
if(key[j] == action[i][0]) {
key[j] = 0;
break;
}
}
}
}
}
//输出最终钥匙盒
for(int i = 0; i < n; i++) {
System.out.print(key[i] + " ");
}
}
}
思路:
1.采用LinkedList存储小朋友编号,然后按题意循环,遇到满足条件的就删除结点,剩余一个人时输出它的编号
2.注意删除一个结点时循环指针需要保持原位,不能向后移动
import java.util.Scanner;
import java.util.LinkedList;
public class CSP201712_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
LinkedList circle = new LinkedList();
for(int i = 1; i <= n; i++) {
circle.add(i);
}
int count = 0;
while(circle.size() > 1) {
for(int i = 0; i < circle.size(); i++) {
count++;
if(count%k == 0 || count%10 == k) {
circle.remove(i);
i--; //删除一个结点时循环指针需要保持原位,不能向后移动
if(circle.size() == 1) { // 在循环途中结束游戏,不加这步90分
break;
}
}
}
}
System.out.println(circle.pop());
}
}
思路:
1.创建一个小球类,包括两个元素(位置和方向)
2.判断小球是否在两边端点,在左端点则方向向右,在右端点则方向向左
3.每个时间点按当前方向前进一格,向右则++,向左则--
4.一个时间点的小球全部移动完后判断是否产生碰撞,循环整个数组判断有没有相同的,若有则产生碰撞的两个小球方向变为各自的反方向
import java.util.Scanner;
class Ball {
public int location;
public String direction = "right";
}
public class CSP201803_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int L = sc.nextInt();
int t = sc.nextInt();
Ball[] ball = new Ball[n];
for(int i = 0; i < n; i++) {
ball[i] = new Ball();
ball[i].location = sc.nextInt();
}
for(int i = 0; i < t; i++) {
for(int j = 0; j < n; j++) {
//碰到左端点则方向转为“右”
if(ball[j].location == 0) {
ball[j].direction = "right";
}
//碰到右端点则方向转为“左”
if(ball[j].location == L) {
ball[j].direction = "left";
}
//每次按当前方向前进一格
if(ball[j].direction.equals("right")) {
ball[j].location++;
}else {
ball[j].location--;
}
}
//两球相碰时方向变为各自的反方向,循环整个数组判断有没有相同的
for(int j = 0; j < n; j++) {
for(int k = j+1; k < n; k++) {
if(ball[j].location == ball[k].location) {
if(ball[j].direction.equals("right")) {
ball[j].direction = "left";
ball[k].direction = "right";
}else {
ball[j].direction = "right";
ball[k].direction = "left";
}
}
}
}
}
//输出最后所有小球的位置
for(int i = 0; i < n; i++) {
System.out.print(ball[i].location + " ");
}
}
}
思路:
1.用一个数组存储 H 和 W 共同装车的时间,0 表示该时间无人装车,1 表示该时间有一人装车,2 表示该时间有两人装车,有2人装车时即为可聊天时间
2.数组下标表示装车时间,但凡该时间段有人在装车,则该时间++
3.因为算的是时间段,所以注意判断一段时间时应为左闭右开区间,算了左边右边就不算了
import java.util.Scanner;
public class CSP201809_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int arr[] = new int[1000001];
for(int i = 0; i < 2*n; i++) {
int left = sc.nextInt();
int right = sc.nextInt();
for(int j = left; j < right; j++) {
arr[j]++;
}
}
int sum = 0;
for(int i = 0; i < 1000001; i++) {
if(arr[i] == 2) {
sum++;
}
}
System.out.println(sum);
}
}
思路:
1.首先注意红绿灯顺序为“红-绿-黄”,从第一题“201812-1:小明上学”的题目中可以得到。
2.红绿灯会一直循环交替变换,所以将红绿灯用一个区间表示,判断每次遇到灯时是什么灯则只需要判断当前落在哪一个区间即可,当时间太长时,红绿灯可能已经过了好几轮了,所以我们求走到红绿灯时候的状况要 %(r+g+y),每个灯的区间如下:
4.遇到路时直接加上该路段所花费时间;遇到红灯时停,需加上还剩多少秒红灯;遇到绿灯不花时间,所以直接跳过;遇到黄灯时需加上还剩多少秒黄灯并且加上一段完整的红灯时间。
5.特别注意:n 最大取值 10^5, 红绿灯时间最大取值 10^6,所以最后结果最大可能取值 10^11,超出了 int 的范围,只能使用 long 才能满分,使用 int 只能得60分。
import java.util.Scanner;
public class CSP201812_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int r = sc.nextInt();
int y = sc.nextInt();
int g = sc.nextInt();
int n = sc.nextInt();
int[][] arr = new int[n][2];
long time = 0; //n 最大取值 10^5, 红绿灯时间最大取值 10^6,所以最后结果最大可能取值 10^11,超出了 int 的范围,只能使用 long 才能满分,使用 int 只能得60分。
for(int i = 0; i < n; i++) {
for(int j = 0; j < 2; j++) {
arr[i][j] = sc.nextInt();
}
long second = 0;
/*
* 红绿灯会一直循环交替变换,所以将红绿灯用一个区间表示,判断每次遇到灯时是什么灯则只需要判断当前落在哪一个区间即可
* 当时间太长时,红绿灯可能已经过了好几轮了,所以我们求走到红绿灯时候的状况要 %(r+g+y)
*/
if(arr[i][0] == 0) { //遇到路时直接加上该路段所花费时间
time += arr[i][1];
continue;
}else if(arr[i][0] == 1) {
second = (time - arr[i][1] + r) % (r + g + y);
}else if(arr[i][0] == 2) {
second = (time - arr[i][1]) % (r +g +y);
}else if(arr[i][0] == 3) {
second = (time - arr[i][1] + r + g) % (r + g +y);
}
if(second < r) { //遇到红灯时停,需加上还剩多少秒红灯
time += r - second;
}else if(second > (r+g)) { //遇到黄灯时需加上还剩多少秒黄灯并且加上一段完整的红灯时间。
time += (r+g+y) - second + r;
}
}
System.out.println(time);
}
}
思路:
1.首先将第一个数存入栈中,遇到'+'号:将'+'号后面的数字存入栈,遇到'-'号:将'-'号后面的数字变为负数后存入栈,遇到'x'号:将栈顶元素弹出并和'x'号后面的数字相乘,将结果存入栈,遇到'/'号:将栈顶元素弹出并和'x'号后面的数字相除,将结果存入栈,最后将栈中的所有元素相加即为表达式的计算结果。
import java.util.Scanner;
import java.util.Stack;
public class CSP201903_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String[] str = new String[n];
Stack stack = new Stack<>();
for(int i = 0; i < n; i++) {
str[i] = sc.next();
stack.push(str[i].charAt(0) - '0'); //栈里存入第一个数
for(int j = 1; j < 7; j++) {
if(str[i].charAt(j) == '+') { //遇到'+'号:将'+'号后面的数字存入栈
stack.push(str[i].charAt(++j) - '0');
}else if(str[i].charAt(j) == '-') { //遇到'-'号:将'-'号后面的数字变为负数后存入栈
int temp = -1 * (str[i].charAt(++j) - '0');
stack.push(temp);
}else if(str[i].charAt(j) == 'x') { //遇到'x'号:将栈顶元素弹出并和'x'号后面的数字相乘,将结果存入栈
int temp = stack.pop() * (str[i].charAt(++j) -'0');
stack.push(temp);
}else if(str[i].charAt(j) == '/') { //遇到'/'号:将栈顶元素弹出并和'x'号后面的数字相除,将结果存入栈
int temp = stack.pop() / (str[i].charAt(++j) - '0');
stack.push(temp);
}
}
//将栈中的所有元素相加
int sum = 0;
while(!stack.isEmpty()) {
sum += stack.pop();
}
if(sum == 24) {
str[i] = "Yes";
}else {
str[i] = "No";
}
}
for(int i = 0; i < n; i++) {
System.out.println(str[i]);
}
}
}