蓝桥杯JavaB国二小白分享一些蓝桥杯的经验
2023-6-16------------------------------------------------------------
2023-6-5------------------------------------------------------------
常见的技巧、遇到的坑
- 提交时记得导包!!!
- 连乘、连加时int溢出
- 除0错误
- 数组内存没开够
- 注意看数范围,如果有累加或者相乘的,考虑是否会溢出int。
- 深搜或广搜时记得用用判重数组记录是否已遍历过
- 遇到题目强调数据无重复时,如1-n的排列或26个字母的排列,可用其当作数组下标存储相应信息
- 遇到要取一半或除2或除x时记得用在除之前转换成double
- 格式化输出System.out.printf(“%.4f”,res);注意不要写(“%0.4lf”,res);
- 定义静态全局变量时,不要在定义时初始化,要在函数中初始化,这样才能保证系统测试样例时每次都会初始化,不然只会初始化依次,如:
static ArrayList<Character> list;
static int vis[];
public int function(String tiles) {
list = new ArrayList<>();
vis = new int[n];
}
- (原本a,b为int时),为防止溢出,转long类型时需这样写 res = (long)a * b; 不能写成res = (long)(a * b); 因为a和b相乘后已经溢出,再转换已经没用了 ,在运算前就要转long,使其有足够的位数进行运算
- 重写compare方法
Arrays.sort(arr, new Comparator<Integer>() {
//重写compare方法
public int compare(Integer a, Integer b) {
//返回值>0交换
return b-a;
}
});
- 输入输出优化,记得抛出异常,最后记得写out.flush();
public class Input_and_output {
static String s[];
static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException {
s = in.readLine().trim().split(" ");
int a = Integer.parseInt(s[0]);
out.println(a);
s = in.readLine().trim().split(" ");
out.println(s[0]);
out.flush();
}
}
常用模板
- 判断日期
#include <iostream>
using namespace std;
bool isLeap(int y){
return (y%4==0&&y%100!=0)||(y%400==0);
}
bool check(int year,int month,int day){//判断是否为合法日期
if(month>12||month==0) return false;
if(day>31) return false;
if(month==2){
if(isLeap(year)&&day>29)
return false;
if(!isLeap(year)&&day>28)
return false;
}
if(month==4||month==6||month==9||month==11){
if(day>30) return false;
}
return true;
}
int main()
{
int n,i;
cin>>n;
int a,b,c,d,e,f,g,h;//8位数字
int year,month,day;
bool flag=false;
for(i=n+1;i<=99999999;i++){
year=i/10000;
month=(i%10000)/100;
day=i%100;
a=i%10;
b=(i/10)%10;
c=(i/100)%10;
d=(i/1000)%10;
e=(i/10000)%10;
f=(i/100000)%10;
g=(i/1000000)%10;
h=(i/10000000)%10;
if(a==h&&b==g&&c==f&&d==e&&flag==false){
if(check(year,month,day)){
cout<<i<<endl;
flag=true;//只输出一个回文
}
}
if(a==h&&b==g&&c==f&&d==e&&a==c&&b==d){
if(check(year,month,day)){
cout<<i<<endl;
break;
}
}
}
return 0;
}
- 并查集
static int N = 1000010;
static int pre[] = new int[N]; //节点i的祖宗是pre[i]
//初始化,下标从1开始,每个节点的祖先是自己
static void init(){
for (int i = 1; i <= n; i++) {
pre[i] = i;
}
}
//找一个节点的祖宗节点
static int find(int x) {
if (x == pre[x]) //父节点等于自己,自己就是祖宗
return x;
return pre[x] = find(pre[x]);//不断往上寻找父节点
}
//合并两个节点
static void union(int a, int b) {
a = find(a);
b = find(b);
//判断两个节点的祖先是否相同,若不相同,则合并之
if (a != b)
pre[a] = b;
}
例题 亲戚
题解:
import java.util.*;
import java.io.*;
//1:无需package
//2: 类名必须Main, 不可修改
public class Main {
static int N = 1000010;
static int pre[] = new int[N];
static int find(int x) {
if (x == pre[x])
return x;
return pre[x] = find(pre[x]);
}
static void union(int a, int b) {
a = find(a);
b = find(b);
//判断两个节点的祖先是否相同,若不相同,则合并之
if (a != b)
pre[a] = b;
}
static String s[];
static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException{
s = in.readLine().trim().split(" ");
int n = Integer.parseInt(s[0]);
int m = Integer.parseInt(s[1]);
//初始化,下标从1开始,每个人的祖先是自己
for (int i = 1; i <= n; i++) {
pre[i] = i;
}
for (int i = 0; i < m; i++) {
s = in.readLine().trim().split(" ");
int a = Integer.parseInt(s[0]);
int b = Integer.parseInt(s[1]);
if (find(a) != find(b))
union(a, b);
}
s = in.readLine().trim().split(" ");
int q = Integer.parseInt(s[0]);
int ans = 0;
for (int i = 0; i < q; i++) {
s = in.readLine().trim().split(" ");
int a = Integer.parseInt(s[0]);
int b = Integer.parseInt(s[1]);
if (find(a) == find(b))
out.println("Yes");
else
out.println("No");
}
out.flush();
}
}
- Dijkstra最短路
public class Main {
static final int max = 10000;
public static void main(String[] args) throws IOException {
// BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] matrix = new int[n+1][n+1];
for (int i = 0; i < matrix.length; i++)
for (int j = 0; j < matrix.length; j++)
matrix[i][j] = max;
for (int i = 0; i < m; i++) {
int source = sc.nextInt();
int target = sc.nextInt();
int weight = sc.nextInt();
if(matrix[source][target] > weight)
matrix[source][target] = weight;
if(matrix[target][source] > weight)
matrix[target][source] = weight;
}
dijkstra(matrix, 1);
}
static void dijkstra(int[][] matrix,int source){
int[] shortest = new int[matrix.length];
int[] visied = new int[matrix.length];
String[] path = new String[matrix.length];
for (int i = 0; i < path.length; i++) {
path[i] = new String(source +"->" + i);
}
shortest[source] = 0;
visied[source] = 1;
for (int i = 1; i < matrix.length; i++) {
int min = Integer.MAX_VALUE , index = -1;
for (int j = 0; j < matrix.length; j++) {
if(visied[j] == 0 && matrix[source][j] < min) {
min = matrix[source][j];
index = j;
}
}
shortest[index] = min;
visied[index] = 1;
for (int j = 0; j < matrix.length; j++) {
if(visied[j] == 0 && matrix[source][j] > matrix[source][index] + matrix[index][j] ) {
matrix[source][j] = matrix[source][index] + matrix[index][j];
path[j] = path[index] + "->" + j;
}
}
}
// for (int i = 0; i < matrix.length; i++) {
// if(shortest[i] != max)
// System.out.println(path[i]+"="+matrix[source][i]);
// }
System.out.println(shortest[matrix.length-1]);
}
}
- 数位DP
例题 统计整数数目
class Solution {
static int max,min , mem[][] , MOD = (int)1e9+7;
public int count(String num1, String num2, int min_sum, int max_sum) {
max = max_sum;min = min_sum;
int nums1[] = new int[num1.length()];
int nums2[] = new int[num2.length()];
int num1_sum = 0;
for(int i = 0; i < num1.length(); i++){
nums1[i] = num1.charAt(i) - '0';
num1_sum += nums1[i];
}
for(int i = 0; i < num2.length(); i++){
nums2[i] = num2.charAt(i) - '0';
}
int t = (num1_sum >=min && num1_sum <= max) ? 1:0;
return (count(nums2) - count(nums1) + MOD + t) % MOD;// 避免负数 (坑)
}
//因为有两部分的dfs,两个部分的dfs不能共用一个mem数组,所以必须分别对每一个dfs用一个mem数组(坑)
int count(int nums[]){
mem = new int[30][410];
for (int i = 0; i < 30; i++)
Arrays.fill(mem[i],-1);
return dfs(0,0,nums,true);
}
int dfs(int i , int sum, int nums[] , boolean is_limit){
if(sum > max) return 0; // 提前结束
if(i == nums.length) return sum >= min ? 1 : 0;
if(!is_limit && mem[i][sum] != -1) return mem[i][sum]; //记忆化搜索
int res = 0;
int up = is_limit ? nums[i] : 9; //根据是否有限制决定上限
//枚举每一位选什么,每一位都可以从0开始选择(即j=0)
for(int j = 0; j <= up; j++){
res = (res + dfs(i+1 , sum + j , nums , is_limit && j == up)) % MOD ;
}
if(!is_limit) mem[i][sum] = res; //不可省略,因为res由is_limit、i、sum三个维度决定
return res;
}
}
- 分组背包
例题 摆花
public class 摆花 {
static int MOD = (int)1e6+7 , mem[][];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int nums[] = new int[n];
mem = new int[110][110];
for (int i = 0; i < mem.length; i++) {
Arrays.fill(mem[i],-1);
}
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
System.out.println( dfs(n-1, m, nums));
}
/*
* 原问题:用前i种花,完成m个盆摆放
* 子问题:假设第i种花选了k盆, 则需要用前i-1种花,完成m-k个盘摆放
*/
static int dfs(int i, int m ,int nums[]) {
if (i < 0) {
return m == 0 ? 1 : 0;
}
if(mem[i][m] != -1) return mem[i][m];
int res = 0;
// 枚举每种花选多少盆
for (int k = 0; k <= nums[i]; k++) {
if (k > m)
break;
res = (res + dfs(i - 1, m - k , nums)) % MOD;
}
return mem[i][m] = res;
}
}
- 快速幂
//快速幂
static long quick_power(long base , long power) {
long res = 1;
while(power>0) {
if((power&1)==1) res = res * base % MOD;
base = base*base % MOD;
power >>= 1;
}
return res%MOD;
}
- BFS
public class BFS {
static int N = 3010;
static char a[][] = new char[N][N];
static int r,c;
static int bfs(Node start,Node end) {
int dis[][] = new int[N][N];
Queue<Node> q = new LinkedList<Node>();
q.offer(start);
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
while(!q.isEmpty()) {
Node t = q.poll();
for (int i = 0; i < 4; i++) {
int newx = t.x + dx[i];
int newy = t.y + dy[i];
if(newx >= r||newx < 0||newy >= c||newy < 0) continue;
if(a[newx][newy] == '#') continue;
if(dis[newx][newy] != 0) continue;
// System.out.println("("+newx+","+newy+")");
dis[newx][newy] = dis[t.x][t.y]+1;
if(newx==end.x && newy==end.y)
return dis[newx][newy];
Node newNode = new Node(newx,newy);
q.offer(newNode);
}
}
return 0;
}
static String s[];
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out) ));
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();
Node start = null,end=null;
for (int k = 0; k < m; k++) {
r = scanner.nextInt();
c = scanner.nextInt();
for (int i = 0; i < r; i++) {
String str = scanner.next();
for (int j = 0; j < c; j++) {
a[i][j] = str.charAt(j);
if(a[i][j] == 'S') start = new Node(i,j);
if(a[i][j] == 'E') end = new Node(i,j);
}
}
int dis = bfs(start, end);
if(dis == 0) System.out.println("oop!");
else System.out.println(dis);
}
}
}
class Node{
int x,y;
public Node() {}
public Node(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
- DFS
例题 网格图中鱼的最大数目
public class Main{
class Solution {
static int cnts[][] = new int[11][11], st[][], cnt = 0;
public int findMaxFish(int[][] grid) {
st = new int[11][11];
int max = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
cnt = 0;
dfs(i, j, grid);
cnts[i][j] = cnt;
System.out.println(cnt);
if (cnts[i][j] > max)
max = cnts[i][j];
}
}
return max;
}
void dfs(int r, int c, int[][] grid) {
if (st[r][c] == 1)
return;
if (grid[r][c] == 0)
return;
else {
st[r][c] = 1;// 标记已访问过的节点
cnt += grid[r][c];
if (c + 1 < grid[0].length)
dfs(r, c + 1, grid);
if (c > 0)
dfs(r, c - 1, grid);
if (r + 1 < grid.length)
dfs(r + 1, c, grid);
if (r > 0)
dfs(r - 1, c, grid);
}
return;
}
}
}
常用思想
- 贡献法
一般用于模拟会超时或超内存,这时只需要考虑每次操作对答案有什么贡献、影响,只记录这些操作贡献、影响,从而节省时间内存 - 前缀和
操作中有大量的重复计算 - 二分
用于有序的序列中,一般在排序操作后可以想想会不会用到二分