第八届蓝桥杯省赛JavaB组

  1. 购物单
    思路:掏出计算器或者把数据处理一下计算,注意每次最少只能取100,结果是5136.85,应该取5200
    答案:5200
  2. 纸牌三角形
    答案:144
    分析:
    在这里插入图片描述
    题目要求三角形三边和都相等。假设把这个三角形按照从左向右的顺序映射到一位数组0 - 8
    那么只需要各个边的和a[0,1,2,3] == a[3,4,5,6] == a[6,7,8,0]
    三角形可以旋转和镜像都算同一种情况,一种三角形有镜像和非镜像2种情况,通过旋转可以得到3种三角形,那么每次共有6种情况。
    可以通过对1 - 9 全排列找出所有满足条件的情况,再除6
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
 
public class Main{
    static int p[] = new int[15];
    static int a[] = {1,2,3,4,5,6,7,8,9};
    static boolean st[] = new boolean[15];
    static Set<String> S = new HashSet<String>();
    static long res = 0;
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        dfs(0);
        System.out.println(res/6);
    }
    static void dfs(int k) {
        if(k == 9) {
            if(check()) res++;
            return;
        }
        for(int i = 0; i < 9; i++) {
            if(st[i]) continue;
            p[k] = a[i];
            st[i] = true;
            dfs(k+1);
            st[i] = false;
        }
    }
    static boolean check() {
        int a = p[0] + p[1] + p[2] + p[3];
        int b = p[3] + p[4] + p[5] + p[6];
        int c = p[6] + p[7] + p[8] + p[0];
        return a == b && b == c;
    }
}
  1. 承压计算
    答案:72665192664

分析:每块金属都会把它的重量均匀的分到它下一层的左边和右边。
假设 f[i][j] = w; 它的重量的一半w/2就会分别分到 f[i+1][j] 和 f[i+1][j+1]
只需要找出最底层的最大重量max 和 min,根据转换
在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.Vector;
 
public class Main{
    static double p[][] = new double[35][35];
    static double f[][] = new double[35][35];
     
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        Scanner sc = new Scanner(System.in);
//      for(int i = 1; i <= 29; i++) {
//          for(int j = 1; j <= i; j++) {
//              f[i][j] = sc.nextDouble();
//          }
//      }
//      for(int i = 1; i <= 29; i++) {
//          for(int j = 1; j <= i; j++) {
//              f[i+1][j] += f[i][j] / 2;
//              f[i+1][j+1] += f[i][j] / 2;
//          }
//      }
//      double Max = 0, Min = 9999999.0;
//      for(int i = 1; i <= 30; i++) {
//          Max = Math.max(Max, f[30][i]);
//          Min = Math.min(Min, f[30][i]);
//      }
//      System.out.println(Max+" "+Min);
        //System.out.println((long)(2086458231L * (Max / Min)));
        System.out.println(72665192664L);
    }
}
  1. 魔方状态
    答案:229878
    这题我直接放弃~~~~~~~~~~~~

  2. 最大公共子串(DP)
    答案:a[i-1][j-1] + 1
    分析:假设定义a[i][j] 表示的是长度为i 和长度为j 的字符串的最大公共子串的长度,当c1[i] == c2[j] ,最后一个字符是不变的,我们只需要看看变的部分是最大公共子串的长度是多少在+1。即变的部分是前a[i-1][j-1], 根据定义表示的是长度为i-1和j-1的字符串的最大公共子串的最大值
    在这里插入图片描述

  3. 日期问题(枚举)
    判断是闰年:(year % 100 != 0 && year % 4 == 0) || year % 400 == 0

代码1:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	static int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	
	static boolean check(int year,int month, int day) {
		if(month < 1 || month > 12) return false;
		if(day == 0 || month != 2 && day > days[month]) return false;
		if(month == 2) {
			int flag = 0;
			if(year % 100 != 0 && year % 4 == 0 || year % 400 == 0) flag = 1;
			if(day > 28 + flag) return false;
		}
		return true;
	}
	public static void main(String[] args) throws IOException {
		BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
		
		String str[] = cin.readLine().split("/");
		int a = Integer.parseInt(str[0]);
		int b = Integer.parseInt(str[1]);
		int c = Integer.parseInt(str[2]);
		
		for(int i = 19600101; i <= 20591231; i++) {
			int year = i / 10000;
			int month = i / 100 % 100;
			int day = i % 100;
			if(check(year,month,day)) {
				if((year%100 == a && month == b && day == c) ||
						(month == a && day == b && year%100 == c) ||
						(day == a && month == b && year%100 == c)) {
					System.out.println(String.format("%d-%02d-%02d", year,month,day));
				}
			}
		}
	}
}

代码2:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	static int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	
	static boolean check(int year,int month, int day) {
		if(month < 1 || month > 12) return false;
		if(day == 0 || month != 2 && day > days[month]) return false;
		if(month == 2) {
			int flag = 0;
			if(year % 100 != 0 && year % 4 == 0 || year % 400 == 0) flag = 1;
			if(day > 28 + flag) return false;
		}
		return true;
	}
	public static void main(String[] args) throws IOException {
		BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
		
		String str[] = cin.readLine().split("/");
		int a = Integer.parseInt(str[0]);
		int b = Integer.parseInt(str[1]);
		int c = Integer.parseInt(str[2]);
		
		for(int i = 1960; i <= 2059; i++) {
			for(int j = 1; j <= 12; j++) {
				//年月日
				if(a == i % 100 && b == j) {
					if(check(i,j,c))
						System.out.println(String.format("%d-%02d-%02d",i,j,c));
				}else if(a == j && c == i % 100) {//月日年
					if(check(i,j,b))
						System.out.println(String.format("%d-%02d-%02d",i,j,b));
				}else if(b == j && c == i % 100) {//日月年
					if(check(i,j,a))
						System.out.println(String.format("%d-%02d-%02d",i,j,a));
				}
			}
		}
	}
}
  1. 包子凑数(完全背包+数论)

1、(a1,a2,…,an) = d > 1 (最大公约数),那么只要不是d的倍数就不能被凑出来,所以有INF个。

2、(a1,a2,…,an) = 1,说明它们不能凑出的数一定是有限个。

==》这里用到裴蜀定理 ,任意两个数的组合必定是他们gcd的倍数,同样可以推广到更多数:如果这些数的gcd是是d,那么他们的组合是d的倍数,如果d不是1,那么必然有无限个数无法被组合出来。

==》公式:当gcd(a,b) = 1, 那么a和b是互质的,a,b最大不能表示出的数是(a-1)*(b-1) - 1

99和98是100内最大的互质的数,不超过10000,那么上界我们就取10000。

因此可以在1 - 10000里面考虑不能被凑出来的数

完全背包:

凑的数 ==》背包容量, Ai 表示物品
在这里插入图片描述

朴素版代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	
	static int N = 10010;
	static int n;
	static boolean f[][] = new boolean[110][N];
	static int a[] = new int[N];
	
	static int gcd(int a,int b) {
		return b == 0 ? a : gcd(b,a%b);
	}
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
		
		n = Integer.parseInt(cin.readLine());
		int d = 0;
		for(int i = 1; i <= n; i++) {
			a[i] = Integer.parseInt(cin.readLine());
			d = gcd(d,a[i]);
		}
		
		if(d != 1) System.out.println("INF");
		else {
			f[0][0] = true;
			for(int i = 1; i <= n; i++)
				for(int j = 0; j < N; j++) {
					f[i][j] = f[i-1][j];
					if(j >= a[i]) f[i][j] = f[i][j] | f[i][j - a[i]];
				}
			int res = 0;
			for(int i = 0; i < N; i++)
				if(!f[n][i]) res++;
			System.out.println(res);
		}
			
	}
}

优化空间:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	
	static int N = 10010;
	static int n;
	static boolean f[] = new boolean[N];
	static int a[] = new int[N];
	
	static int gcd(int a,int b) {
		return b == 0 ? a : gcd(b,a%b);
	}
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
		
		n = Integer.parseInt(cin.readLine());
		int d = 0;
		for(int i = 1; i <= n; i++) {
			a[i] = Integer.parseInt(cin.readLine());
			d = gcd(d,a[i]);
		}
		
		if(d != 1) System.out.println("INF");
		else {
			f[0] = true;
			for(int i = 1; i <= n; i++)
				for(int j = a[i]; j < N; j++)
					f[j] = f[j] | f[j - a[i]];
			
			int res = 0;
			for(int i = 0; i < N; i++)
				if(!f[i]) res++;
			System.out.println(res);
		}
			
	}
}
  1. 分巧克力(二分)
    分析:题目要求在保证每个人最、至少得到一块巧克力的前提下尽可能把巧克力切的更大。
    假设我们确定边长x,那么只需要判断n块巧克力能不能切出边长为x的巧克力的数量是否大于k。
    根据数据范围,x最小为1,最大为100000,所求的答案在1 - 100000里,二分枚举。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
 
public class Main{
    static int N = 100010;
    static int n,m;
    static int h[] = new int[N];
    static int w[] = new int[N];
     
    static boolean check(int mid) {
        int res = 0;
        for(int i = 0; i < n; i++)
                res += (h[i] / mid) * (w[i] / mid);
        return res >= m;
    }
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        String str[] = cin.readLine().split(" ");
        n = Integer.parseInt(str[0]);
        m = Integer.parseInt(str[1]);
         
        for(int i = 0; i < n; i++) {
            str = cin.readLine().split(" ");
            h[i] = Integer.parseInt(str[0]);
            w[i] = Integer.parseInt(str[1]);
        }
        int l = 0, r = 1000000;
        while(l < r) {
            int mid = l + r + 1>> 1;
            if(check(mid)) l = mid;
            else r = mid - 1;
        }
        System.out.println(l);
    }
}
  1. K倍区间(前缀和)

暴力算法(n^2 + 前缀和)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
     
    static int N = 100010;
    static long s[] = new long[N];
    static long cnt[] = new long[N];
    static int n,k;
     
    public static void main(String[] args) throws IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
         
        String str[] = cin.readLine().split(" ");
        n = Integer.parseInt(str[0]);
        k = Integer.parseInt(str[1]);
         
        for(int i = 1; i <= n; i++) {
            s[i] = Long.parseLong(cin.readLine());
            s[i] += s[i-1];
        }
         
        long res = 0;
        for(int l = 1;  l <= n; l++)
            for(int r = l; r <= n; r++)
                if((s[r] - s[l-1]) % k == 0) res++;
        System.out.println(res);
    }
     
}

优化版(O(n) + 前缀和)
在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
     
    static int N = 100010;
    static long s[] = new long[N];
    static long cnt[] = new long[N];
    static int n,k;
     
    public static void main(String[] args) throws IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
         
        String str[] = cin.readLine().split(" ");
        n = Integer.parseInt(str[0]);
        k = Integer.parseInt(str[1]);
         
        for(int i = 1; i <= n; i++) {
            s[i] = Long.parseLong(cin.readLine());
            s[i] += s[i-1];
        }
         
        long res = 0;
        cnt[0]++;
        for(int i = 1; i <= n; i++) {
            res += cnt[(int)(s[i] % k)];
            cnt[(int)(s[i] % k)]++;
        }
        System.out.println(res);
    }
     
}

C++组题目:

标题:等差素数列(DFS)
答案:210
分析:暴力枚举,先把10000以内的素数找出来放到st,暴搜的时候直接查。
我们要找长度为数列长度为10的数列且公差最小,那么从小到大枚举公差,确定一个公差的值后,再枚举素数,每次加上公差,当枚举出的素数个数为10的时候,此时的d就是最小的公差。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	
	static boolean st[] = new boolean[100010];
	static int p[] = new int[20];
	
	static boolean is_prime(int x) {
		for(int i = 2; i <= x / i; i++)
			if(x % i == 0) return false;
		return true;
	}
	
	static void dfs(int k,int x,int d) {
		if(k == 10) {
			System.out.println(d);
			for(int i = 0; i < 10; i++) System.out.print(p[i]+" ");
			System.out.println();
			return;
		}
		if(st[x+d]) {
			p[k] = x + d;
			dfs(k+1,x+d,d);
		}
	}
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
		
		int arr[] = new int[10000];
		int t = 0;
		for(int i = 2; i < 100000; i++)
			if(is_prime(i)) st[i] = true;
		
		for(int d = 2; d <= 500; d++) {
			for(int j = 2; j <= 500; j++) {
				p[0] = j;
				if(st[j]) dfs(1,j,d);
			}
		}
		//System.out.println(210);
	}
}

标题:方格分割(DFS)
答案:509
分析:从其他大佬处学到的方法
在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	
	static boolean st[][] = new boolean[10][10];
	static int dx[] = {0,1,0,-1};
	static int dy[] = {1,0,-1,0};
	static int res = 0;
	static void dfs(int x,int y) {
		if(x == 0 || y == 0 || x == 6 || y == 6) {
			res++;
			return;
		}
		for(int i = 0; i < 4; i++) {
			int a = x + dx[i];
			int b = y + dy[i];
			if(a < 0 || a > 6 || b < 0 || b > 6) continue;
			if(st[a][b]) continue;
			st[a][b] = st[6-a][6-b] = true;
			dfs(a,b);
			st[a][b] = st[6-a][6-b] = false;
		}
	}
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
		
		st[3][3] = true;  //注意点
		dfs(3,3);
		System.out.println(res/4);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值