目录
试题A:星期计算
试题B:山
试题C:字符统计
试题D:最少刷题数
试题E:求阶乘
试题F:最大子矩阵
试题G:数组切分
试题H:回忆迷宫
// 十三届省赛第一题,星期计算
public static void f1() {
// 不算结果取模即可,缓存无限大
int res = (int) (Math.pow(20, 22) % 7 + 6);
System.out.println(res);
}
// 十三届省赛第二题,山:暴力
public static void f2() {
long res = 0;
for (int i = 2022; i <= 2022222022; i++) {
if (check1(i + "")) {
// System.out.println(i);
res++;
}
}
System.out.println(res);
}
public static boolean check1(String str) {
int len = str.length();
// 前大半不减
for (int i = 0; i < len - len / 2 - 1; i++) {
if (str.charAt(i) > str.charAt(i + 1)) {
return false;
}
}
// 后小半回文
for (int i = len - len / 2; i < len; i++) {
if (str.charAt(i) != str.charAt(len - i - 1)) {
return false;
}
}
return true;
}
// 方法二,优化:按位数分类,注意头尾
public static void f3() {
long res = 0;
for (int i = 21; i <= 99; i++) {
if (check2(i + "")) {
res++;
}
}
for (int i = 111; i <= 9999; i++) {
if (check2(i + "")) {
res += 2;
}
}
for (int i = 11111; i <= 99999; i++) {
if (check2(i + "")) {
// System.out.println(i);
res++;
}
}
for (int i = 11111; i <= 20221; i++) {
if (check2(i + "")) {
res++;
}
}
System.out.println(res);
}
public static boolean check2(String str) {
char[] chs = str.toCharArray();
Arrays.sort(chs);
if (Arrays.equals(chs, str.toCharArray())) {
return true;
}
return false;
}
// 十三届省赛第三题,字符统计
public static void f4(String str) {
// Z的ascll=90
int[] arr = new int[100];
for (int i = 0; i < str.length(); i++) {
arr[str.charAt(i)]++;
}
int max = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == max) {
// 顺序拿出即为有序
System.out.print((char) i);
}
}
}
// 十三届省赛第四题,最少刷题数(排序后,查找一遍,遍历计算所有结果)
public static void f5(List list, List sist) {
int num = sist.get(sist.size() / 2);
int pre = sist.indexOf(num);
int next = sist.size() - 1 - sist.lastIndexOf(num);
for (int i = 0; i < list.size(); i++) {
int temp = list.get(i);
//大的比小的少
if(next
试题E:求阶乘
//十三届省赛第五题,求阶乘:二分查找阶乘的值
public static long f6(long k) {
//先确定边界
long l=-1,r;
long p=1;//外拓指针
while (f7(p)=k) {
r=m;
}else {
l=m;
}
}
if(f7(r)==k) {
return r;
}else {
//处理没有的情况,如k=5
return -1;
}
}
//欧几里得找5的因子即为0的个数(处理没有的情况,如sum=5)
public static long f7(long m) {
long n=m;
long sum=0;
//欧几里得公式
while (n>0) {
sum+=n/5;
n/=5;
}
return sum;
}
试题F:最大子矩阵
// 具有列最大最小值的变形一维数组变形一维求最大子数组(优化:sum预算+跳列遍历)
public static int f3(int lim, int[][] arr) {
int sum = 0;// 变形子数组的最大元素个数(0表示单列不满足)
flag: for (int i = 0; i < arr[0].length; i++) {
int smin = arr[0][i], smax = arr[1][i];
if (smax - smin <= lim) {
sum = Math.max(1, sum);
} else {
continue flag;
}
int sminy = i, smaxy = i;// 记录左极端值的列
for (int j = i + 1; j < arr[0].length; j++) {
// System.out.println(i+" "+j);
if (arr[1][j] > smax) {
if (arr[1][j] - smin > lim) {
i = Math.min(sminy, smaxy);// 跳列遍历
continue flag;
}
smax = arr[1][j];
smaxy = j;
}
if (arr[0][j] < smin) {
if (smax - arr[0][j] > lim) {
i = Math.min(sminy, smaxy);// 跳列遍历
continue flag;
}
smin = arr[0][j];
sminy = j;
}
if (j - i + 1 > sum) {// 此子数组的元素个数
sum = j - i + 1;
}
if (sum >= arr[0].length - i) {// 预算此子数组最大个数,是否还需要遍历
break flag;
}
}
}
return sum;
}
// 十三届省赛第六题,最大子矩阵:二维化一维(枚举行组合)
public static int f4(int lim, int[][] table) {
int sum = 1;
int[][] arr = new int[2][table[0].length];// 具有列最大最小值的变形一维数组
for (int i = 0; i < table.length; i++) {
for (int j = i; j < table.length; j++) {
for (int k = 0; k < arr[0].length; k++) {// 组合为具有列最大最小值的变形一维数组
arr[0][k] = table[i][k];// 初始化
arr[1][k] = table[i][k];// 初始化
for (int t = i; t <= j; t++) {
arr[0][k] = Math.min(table[t][k], arr[0][k]);
arr[1][k] = Math.max(table[t][k], arr[1][k]);
}
}
int mid = f3(lim, arr);
// System.out.println(Arrays.toString(arr[0]));
// System.out.println(Arrays.toString(arr[1]));
// System.out.println(mid);
sum = Math.max(mid * (j - i + 1), sum);
Arrays.fill(arr[0], 0);// 清除
Arrays.fill(arr[1], 0);// 清除
}
}
return sum;
}
试题G:数组切分
// //十三届省赛第七题,数组切分:动规递推
// 2 1 5 4 3
// 2 :arr[0]=1 =1
// 2 1 :arr[1]=arr[0]+1 =2
// 2 1 5 :arr[2]=arr[1]+0+0 =2
// 2 1 5 4 :arr[3]=arr[2]+arr[1]+0+0 =4
// 2 1 5 4 3:arr[4]=arr[3]+arr[2]+arr[1]+0+1=9
public static long f5(int[] arr) {
long[] dp = new long[arr.length];
dp[0] = 1;// 初始化第一个
for (int i = 1; i < dp.length; i++) {
int min = arr[i], max = arr[i];// 初始化
for (int j = i; j >= 0; j--) {// 后往前求dp[i]
min = Math.min(min, arr[j]);// 维持最小值
max = Math.max(max, arr[j]);// 维持最大值
if (j != 0) {
if (max - min == i - j) {// 核心:最大减最小等于长度则为连续如:(2 1 3:3-1=2-0)
dp[i] += dp[j - 1] % 1000000007;// 处理MOD
}
} else {// 判断整体是否满足
if (max - min == i - j) {// 核心:最大减最小等于长度则为连续如:(2 1 3:3-1=2-0)
dp[i] += 1;
}
}
}
}
// System.out.println(Arrays.toString(dp));
return dp[arr.length - 1] % 1000000007;// 最后再处理MOD
}
试题H:回忆迷宫
// 十三届省赛第八题,回忆迷宫:先填墙(路边+内空)再挖路
static Character[][] table = new Character[300][300];// 取150,150为中心开始
public static void f7(char[] arr) {
int nx = 150, ny = 150, mx = 150, my = 150;// 最小最大的坐标,输出用
for (Character[] cs : table) {
Arrays.fill(cs, ' ');// 初始化
}
int[][] empty = new int[2][arr.length + 1];
int x = 150, y = 150;// 初始化位坐标
empty[0][0] = 150;// 初始化路的x坐标
empty[1][0] = 150;// 初始化路的y坐标
// 填墙
table[x - 1][y] = '*';// 初始化坐标墙
table[x + 1][y] = '*';// 初始化坐标墙
table[x][y - 1] = '*';// 初始化坐标墙
table[x][y + 1] = '*';// 初始化坐标墙
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 'U') {// 上
x--;
} else if (arr[i] == 'D') {// 下
x++;
} else if (arr[i] == 'R') {// 右
y++;
} else if (arr[i] == 'L') {// 左
y--;
}
empty[0][i + 1] = x;// 记录路的x坐标
empty[1][i + 1] = y;// 记录路的y坐标
nx = Math.min(nx, x);// 维持最小x坐标
ny = Math.min(ny, y);// 维持最小y坐标
mx = Math.max(mx, x);// 维持最大x坐标
my = Math.max(my, y);// 维持最大y坐标
table[x - 1][y] = '*';// 填墙
table[x + 1][y] = '*';// 填墙
table[x][y - 1] = '*';// 填墙
table[x][y + 1] = '*';// 填墙
}
// for (int i = nx - 1; i <= mx + 1; i++) {
// for (int j = ny - 1; j <= my + 1; j++) {
// System.out.print(table[i][j]);
// }
// System.out.println();
// }
// System.out.println("==================");
// 填满中间(dfs深搜法,全面)
f8(nx-1,ny-1,mx+1,my+1);
// for (int i = nx - 1; i <= mx + 1; i++) {
// for (int j = ny - 1; j <= my + 1; j++) {
// System.out.print(table[i][j]);
// }
// System.out.println();
// }
// System.out.println("==================");
// 挖空
for (int i = 0; i < empty[0].length; i++) {
table[empty[0][i]][empty[1][i]] = ' ';
}
for (int i = nx - 1; i <= mx + 1; i++) {
for (int j = ny - 1; j <= my + 1; j++) {
System.out.print(table[i][j]);
}
System.out.println();
}
}
//填满中间,dfs深搜
static Character[][] copy=new Character[table.length][];
public static void f8(int nx,int ny,int mx,int my) {//左上右下坐标
for (int i = 0; i < copy.length; i++) {
copy[i]=table[i].clone();//复制表格
}
for (int i = nx; i <= mx; i++) {
for (int j = ny; j <= my; j++) {
if (copy[i][j] == ' ') {// 如果是一个被包围的空格则填墙
dfs(nx, ny, mx, my, i, j);
//填充原表格
if(flag) {
for (int k = 0; k < listx.size(); k++) {
table[listx.get(k)][listy.get(k)]='*';
}
}
//恢复
flag=true;
listx.clear();
listy.clear();
}
}
}
}
static boolean flag=true;
static List listx=new ArrayList();
static List listy=new ArrayList();
public static void dfs(int nx,int ny,int mx,int my,int x,int y) {//左上右下坐标
copy[x][y]='*';
listx.add(x);
listy.add(y);
if(x==nx||x==mx||y==ny||y==my) {
flag=false;
}
if(copy[x][y+1]==' '&&y+1<=my) {
dfs(nx, ny, mx, my, x, y+1);
}
if(copy[x][y-1]==' '&&y-1>=ny) {
dfs(nx, ny, mx, my, x, y-1);
}
if(copy[x+1][y]==' '&&x+1<=mx) {
dfs(nx, ny, mx, my, x+1, y);
}
if(copy[x-1][y]==' '&&x-1>=nx) {
dfs(nx, ny, mx, my, x-1, y);
}
}