代码地址:Algorithm-Question/CCF_CSP at main · LilWingXYZ/Algorithm-Question · GitHub
目录
201312-1:出现次数最多的数
201403-1:相反数
201409-1:相邻数对
201412-1:门禁系统
201503-1:图像旋转
201509-1:数列分段
201512-1:数位之和
201604-1:折点计数
201609-1:最大波动
201612-1:中间数
201703-1:分蛋糕
201709-1:打酱油
201712-1:最小差值
201803-1:跳一跳
201809-1:卖菜
201812-1:小明上学
201903-1:小中大
201909-1:小明种苹果
201912-1:报数
202006-1:线性分类器
202009-1:称检测点查询
202012-1:期末预测之安全指数
202104-1:灰度直方图
202109-1:数组推导
202112-1:序列查询
思路:
1.先排序
2.采用正向双指针,相等的数记下
3.相等或不相等,两个指针都向右,只比较相邻两个是否相等
import java.util.Scanner;
import java.util.Arrays;
public class CSP201312_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
Arrays.sort(arr);
int i = 0;
int j = 1;
int num = 1;
int max = 1;
int result = arr[0];
while(j < arr.length) {
if(arr[i] == arr[j]) {
num++;
if(max < num) {
max = num;
result = arr[i];
}
}else {
num = 1;
}
i++;
j++;
}
System.out.println(result);
}
}
思路:
1.先排序
2.采用反向双指针
3.相反数相加为0
4.绝对值小的指针不动
import java.util.Scanner;
import java.util.Arrays;
import java.lang.Math;
public class CSP201403_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
Arrays.sort(arr);
int i = 0;
int j = n - 1;
int num = 0;
while(i < j) {
if((arr[i] + arr[j]) == 0) {
num++;
i++;
j--;
}
else if(Math.abs(arr[i]) > Math.abs(arr[j])) {
i++;
}
else {
j--;
}
}
System.out.println(num);
}
}
思路:
1.先排序
2.采用正向双指针,相差为1时计数器+1
3.相差为1或不为1,两个指针都往右,只比较相邻两个数
import java.util.Scanner;
import java.util.Arrays;
public class CSP201409_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
Arrays.sort(arr);
int i = 0;
int j = 1;
int num = 0;
while(j < arr.length) {
if(arr[j] - arr[i] == 1) {
num++;
}
i++;
j++;
}
System.out.println(num);
}
}
思路:
1.定义两个数组,一个存输入的数据,一个存读者编号出现的次数(索引为读者编号)
import java.util.Scanner;
public class CSP201412_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arrInput = new int[n];
final int N = 1001;
int[] arrOut = new int[N];
for(int i = 0; i < n; i++) {
arrInput[i] = sc.nextInt();
arrOut[arrInput[i]]++;
System.out.print(arrOut[arrInput[i]] + " ");
}
}
}
思路:
1.定义一个旋转之后的二维数组,读取输入时直接读进这个数组
2.找到旋转之后的索引和旋转之前索引的关系:arr[i][j] 旋转之后为 arr[m-1-j][i]
import java.util.Scanner;
public class CSP201503_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] arr = new int[m][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
arr[m-1-j][i] = sc.nextInt();
}
}
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}
Java内存超限只得到90分,改用C++得到100分
#include
using namespace std;
int main() {
int n,m;
cin>>n>>m;
int arr[m][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
cin>>arr[m-1-j][i];
}
}
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
cout<
思路:
1.采用正向双指针,比较前后两个数是否相等
2.不相等时段数+1,考虑0个数0段和1个数1段的情况
import java.util.Scanner;
public class CSP201509_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int i = 0;
int j = 0;
int num = 0;
while(j < arr.length) {
if(num == 0) {
num++;
}
if(arr[i] != arr[j]) {
num++;
}
if(j == 0) {
j++;
}else{
i++;
j++;
}
}
System.out.println(num);
}
}
思路:
1.通过除法运算和模运算来提取每一位的数
import java.util.Scanner;
public class CSP201512_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int num = 0;
while(n/10 != 0) {
num += n%10;
n /= 10;
}
num += n%10;
System.out.println(num);
}
}
思路:
1.采用正向双指针,比较相邻两个数
2.运用一个flag标记当前是递增还是递减
3.比较当前flag和上一个flag是否一致,不一致则折点数+1
import java.util.Scanner;
public class CSP201604_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int i = 0;
int j = 1;
int num = 0;
int flag = 0;
int judge = 0;
while(j < arr.length) {
judge = flag;
if(arr[i] > arr[j]) {
flag = 1;
}else {
flag = 0;
}
if(j != 1 && judge != flag) {
num++;
}
i++;
j++;
}
System.out.println(num);
}
}
思路:
1.采用正向双指针,计算相邻两个数的差
2.记录下当前最大差值
import java.util.Scanner;
import java.lang.Math;
public class CSP201609_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int i = 0;
int j = 1;
int max = 0;
while(j < arr.length) {
max = (Math.abs(arr[i] - arr[j]) > max) ? Math.abs(arr[i] - arr[j]) : max;
i++;
j++;
}
System.out.println(max);
}
}
思路:
1.先排序
2.二分查找找出第一个中间数的值
3.遍历数组,大于中间数的个数记为max,小于中间数的个数记为min
4.如果min=max,输出中间数,否则输出-1
import java.util.Scanner;
import java.util.Arrays;
public class CSP201612_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
Arrays.sort(arr);
int min = 0, max = 0;
int l = 0, r = arr.length - 1;
int mid = l + (r + l)/2;
for(int i = 0; i < n; i++) {
if(arr[mid] > arr[i]) {
min++;
}else if(arr[mid] < arr[i]) {
max++;
}
}
if(min == max) {
System.out.println(arr[mid]);
}else{
System.out.println(-1);
}
}
}
思路:
1.由题可知至少有一块蛋糕,所以至少一个人分到蛋糕
2.考虑边界极端情况
import java.util.Scanner;
public class CSP201703_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] arr = new int[n];
int num = 1;
int sum = 0;
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
sum += arr[i];
if(sum >= k && i < n-1) {
num++;
sum = 0;
}
}
System.out.println(num);
}
}
思路:
1.买5瓶最划算,所以先判断钱够不够买5瓶
2.当不够买5瓶时判断够不够买3瓶
3.当不够买3瓶时就一瓶一瓶买
import java.util.Scanner;
public class CSP201709_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int money = sc.nextInt();
int num = 0;
while(money >= 50) {
num += 7;
money -= 50;
}
while(money >= 30) {
num += 4;
money -= 30;
}
num += money/10;
System.out.println(num);
}
}
思路:
1.先排序
2.遍历数组,比较相邻两个数差值
3.当相邻两个数相同时,差值为最小的0,可提前跳出循环
import java.util.Scanner;
import java.util.Arrays;
import java.lang.Math;
public class CSP201712_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
Arrays.sort(arr);
int d = 10000;
for(int i = 0; i < n - 1; i++) {
if(arr[i] == arr[i+1]) {
d = 0;
break;
}else {
d = (Math.abs(arr[i] - arr[i+1]) < d) ? Math.abs(arr[i] - arr[i+1]) : d;
}
}
System.out.println(d);
}
}
思路:
1.分别判断0,1,2三种情况
2.当为0,结束
3.当为1,+1分
4.当为2,判断是否第一次或上局得分为1:若是,+2;若不是,+上局得分再+2
import java.util.Scanner;
public class CSP201803_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] arr = new int[30];
int score = 0;
int flag = 0;
int lastScore= 0;
for(int i = 0; i < 30; i++) {
arr[i] = sc.nextInt();
if(arr[i] == 0) {
break;
}else if(arr[i] == 1) {
score++;
lastScore = 0;
flag = 0;
}else if(arr[i] == 2) {
if(flag == 0) {
score += 2;
}else {
score += (lastScore + 2);
}
lastScore += 2;
flag = 1;
}
}
System.out.println(score);
}
}
思路:
1.遍历数组计算平均值
2.注意开头第一个和最后一个
3.注意不能在原数组改,改了之后会影响下一个值的平均值,所以输出到新的数组
import java.util.Scanner;
public class CSP201809_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arrInput = new int[n];
int[] arrOut = new int[n];
for(int i = 0; i < n; i++) {
arrInput[i] = sc.nextInt();
}
for(int i = 0; i < n; i++) {
if(i == 0) {
arrOut[i] = (arrInput[i] + arrInput[i+1])/2;
}else if(i == n-1) {
arrOut[i] = (arrInput[i] + arrInput[i-1])/2;
}else {
arrOut[i] = (arrInput[i] + arrInput[i-1] + arrInput[i+1])/3;
}
System.out.print(arrOut[i] + " ");
}
}
}
思路:
1.此题关键在于读懂题目和样例说明
2.注意黄灯之后是红灯,所以遇到黄灯还得加上整个红灯时长
import java.util.Scanner;
public class CSP201812_1 {
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[2];
int sum = 0;
for(int i = 0; i < n; i++) {
arr[0] = sc.nextInt();
arr[1] = sc.nextInt();
if(arr[0] == 0) {
sum += arr[1];
}else if(arr[0] == 1) {
sum += arr[1];
}else if(arr[0] == 2) {
sum += (arr[1] + r);
}
}
System.out.println(sum);
}
}
思路:
1.最大值和最小值很好输出,关键在于中位数
2.当 n 为奇数时,中位数就是最中间那个数;当为偶数时,中位数则为中间两个数的平均值
3.求平均值时注意要保证输出的数是一个小数
4.最后判断是整数就输出整数,是小数就输出小数
import java.util.Scanner;
public class CSP201903_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
int min = 10000000;
int max = -10000000;
int mid_index = 0;
double mid = 0.0; //保留一位小数
int l = 0, r = arr.length - 1;
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
min = (arr[i] < min) ? arr[i] : min;
max = (arr[i] > max) ? arr[i] : max;
}
mid_index = l + (r - l)/2;
if(n%2 == 0) { //n为偶数
double sum = 0.0;
sum = arr[mid_index] + arr[mid_index + 1];
mid = sum/2; // double/int才能保证最终数有小数点;
// 两整数相加再除以2肯定只有一位小数0.5,所以不用单独考虑四舍五入
}else { //n为奇数
mid = arr[mid_index];
}
if(mid - (int)mid == 0) { //整数就输出整数
System.out.print(max + " " + (int)mid + " " + min);
}else { //输出小数
System.out.print(max + " " + mid + " " + min);
}
}
}
思路:
1.此题关键在于理解题意,明白每一个输出代表什么
import java.util.Scanner;
import java.lang.Math;
public class CSP201909_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] arr = new int[n][m+1];
int[] sumOne = new int[n]; //其中一棵树的总和
int sum = 0;
int max = 0;
int max_index = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j <= m; j++) {
arr[i][j] = sc.nextInt();
sumOne[i] += arr[i][j];
}
sum += sumOne[i];
if(Math.abs(sumOne[i] - arr[i][0]) > max) {
max = Math.abs(sumOne[i] - arr[i][0]);
max_index = i;
}
}
System.out.print(sum + " " + (max_index+1) + " " + max);
}
}
思路:
1.四个人循环报数,采用一个大小为4的for循环,外面再套一层判断数字是否报完的while循环
2.每次都判断数中是否含有数字7或7的倍数,注意不要只关注尾数,71这种也包含7
3.当有一个满足跳过条件时,当前人跳过次数+1,并且最后报的数字往上+1(因为题中着重强掉所报的总数 n 中不计入被跳过的数)
import java.util.Scanner;
public class CSP201912_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int count = 1;
int[] person = new int[4];
int flag = 0; //判断数字中是否含有7的flag。不含7:flag=0;含7:flag=1
while(count <= n) {
for(int i = 0; i < 4; i++) {
if(count > n) {
break;
}
//判断报的数中是否含有7
int countCopy = count;
while(countCopy != 0) {
if(countCopy%10 == 7) {
flag = 1;
}
countCopy /= 10;
}
//满足跳过条件的人跳过数+1
if(count%7 == 0 || flag == 1) {
person[i]++;
n++; //跳过一次则最后报的数字往上+1
}
count++;
flag = 0;
}
}
for(int i = 0; i < 4; i++) {
System.out.println(person[i]);
}
}
}
思路:
1.判断方法:所有同类的点在同一个查询函数里计算出来的最终结果都是正的或是负的,则说明该查询函数能分割所有点;否则,说明该查询函数不能分割所有点
2.几个关键点:
(1) 初始化为 int 类型的数组,所以类别数 A 和 B 输入后转化为 int 类型的 0 和 1
(2) 用Scanner.nextLine读字符时会将空格读入,所以用String.trim()来去除首尾空格
(3) 刚开始并不知道“A”和“B”哪一类可以使查询函数变为正或负,所以先判断“A”和“B”哪一类可以使查询函数变为正或负
(4) 判断每个查询函数是否能分割所有数据点,判断出一个则该类别数量++,能把所有点都分割正确的输出“Yes”,否则输出“No”。
import java.util.Scanner;
public class CSP202006_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] point = new int[n][3]; //数据点
int[][] query = new int[m][3]; //查询函数
//读取数据点
for(int i = 0; i < n; i++) {
for(int j = 0; j < 3; j++) {
//将字符“A”和“B”转换为int数据0和1
if(j == 2) {
String type = sc.nextLine();
type = type.trim(); //去除字符串中的空格
if(type.equals("A")) {
point[i][j] = 0;
}else if(type.equals("B")) {
point[i][j] = 1;
}
break;
}
point[i][j] = sc.nextInt();
}
}
//读取查询函数
for(int i = 0; i < m; i++) {
for(int j = 0; j < 3; j++) {
query[i][j] = sc.nextInt();
}
}
/*
* 判断每个查询函数是否能分割所有数据点
* 判断方法:所有同类的点在同一个查询函数里计算出来的最终结果都是正的或是负的,则说明该查询函数能分割所有点
* 否则,说明该查询函数不能分割所有点
*/
for(int i = 0; i < m; i++) {
//刚开始并不知道“A”和“B”哪一类可以使查询函数变为正或负
//所以先判断“A”和“B”哪一类可以使查询函数变为正或负
int flagMax = 2;
int flagMin = 2;
for(int j = 0; j < n; j++) {
while(flagMax == 2 || flagMin == 2) {
if(query[i][0] + query[i][1] * point[j][0] + query[i][2] * point[j][1] > 0) {
flagMax = point[j][2];
j++;
}else {
flagMin = point[j][2];
j++;
}
}
break;
}
//判断每个查询函数是否能分割所有数据点
//判断出一个则该类别数量++
int max = 0;
int min = 0;
for(int j = 0; j < n; j++) {
if((query[i][0] + query[i][1] * point[j][0] + query[i][2] * point[j][1] > 0) && (point[j][2] == flagMax)) {
max++;
}else if ((query[i][0] + query[i][1] * point[j][0] + query[i][2] * point[j][1] < 0) && (point[j][2] == flagMin)) {
min++;
}
}
//能把所有点都分割正确的输出“Yes”,否则输出“No”
if(max + min == n) {
System.out.println("Yes");
}else {
System.out.println("No");
}
}
}
}
思路:
1.计算(X,Y)和所有点的距离
2.维护最近三个点的值和它们的索引
3.每计算一个点的距离就更新一次最近三个点的数据
import java.util.Scanner;
import java.lang.Math;
public class CSP202009_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int X = sc.nextInt();
int Y = sc.nextInt();
int[][] checkPoint = new int[n][2];
int first = 1000001, firstCloseIndex = 0;
int second = 1000001, secondCloseIndex = 0;
int third = 1000001, thirdCloseIndex = 0;
int d = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < 2; j++) {
checkPoint[i][j] = sc.nextInt();
}
d = (int)Math.pow((X - checkPoint[i][0]), 2) + (int)Math.pow((Y - checkPoint[i][1]), 2);
if(d < first) {
third = second;
thirdCloseIndex = secondCloseIndex;
second = first;
secondCloseIndex = firstCloseIndex;
first = d;
firstCloseIndex = i;
}else if (d < second) {
third = second;
thirdCloseIndex = secondCloseIndex;
second = d;
secondCloseIndex = i;
}else if (d < third) {
third = d;
thirdCloseIndex = i;
}
}
System.out.println(firstCloseIndex + 1);
System.out.println(secondCloseIndex + 1);
System.out.println(thirdCloseIndex + 1);
}
}
上述方法每次都要更新三个值,过于繁琐,所以可采用C++中的 pair 进行简化实现:
#include
#include
#include
using namespace std;
int main() {
int n,x,y;
cin>>n>>x>>y;
int point[n][2];
pair closePoint[n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < 2; j++) {
cin>>point[i][j];
}
int d = (int)pow(x - point[i][0], 2) + (int)pow(y - point[i][1], 2);
closePoint[i] = {d, i};
}
sort(closePoint, closePoint + n);
for(int i = 0; i < 3; i++) {
cout<
或者使用Python中的元组进行简化实现:
import math
n,X,Y = map(int, input().split())
closePoint = []
for i in range(n):
x,y = map(int, input().split())
d = math.pow((X - x), 2) + math.pow((Y - y), 2)
closePoint.append((d, i))
closePoint.sort()
for i in range(3):
print(closePoint[i][1] + 1)
思路:
1.这题就是一个累加和再套一个max函数
import java.util.Scanner;
import java.lang.Math;
public class CSP202012_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] index = new int[n][2];
int x = 0;
int y = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < 2; j++) {
index[i][j] = sc.nextInt();
}
x += index[i][0] * index[i][1];
}
y = Math.max(0, x);
System.out.println(y);
}
}
思路:
1.这题就是用一个数组来装索引值出现的次数
import java.util.Scanner;
public class CSP202104_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int L = sc.nextInt();
int[][] pixel = new int[n][m];
int[] histogram = new int[L];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
pixel[i][j] = sc.nextInt();
histogram[pixel[i][j]]++;
}
}
for(int i = 0; i < L; i++) {
System.out.print(histogram[i] + " ");
}
}
}
思路:
1.A的sum的最大值等于输入的B的值本身
2.当输入的B中的数有连续相同的数时,后者最小可取0
import java.util.Scanner;
public class CSP202109_1 {
public static void main(String []args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] input = new int[n];
for(int i = 0; i < n; i++) {
input[i] = sc.nextInt();
}
int max = 0;
int min = 0;
for(int i = 1; i < n; i++) {
max += input[i-1];
if(input[i-1] == input[i]) {
min += 0;
}else {
min += input[i];
}
}
min += input[0];
max += input[n-1];
System.out.println(max);
System.out.println(min);
}
}
思路:
1.从后往前遍历,使用计数器计算满足条件的索引个数
import java.util.Scanner;
public class CSP202112_1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int N = sc.nextInt();
int[] A = new int[n+1];
A[0] = 0;
for(int i = 1; i < n+1; i++) {
A[i] = sc.nextInt();
}
int sum = 0;
int count = 0;
for(int i = N-1; i >= 0; i--) {
if(i >= A[n]) {
count++;
}else {
sum += n*count;
count = 0;
n--;
i++;
}
}
System.out.println(sum);
}
}