第十二届蓝桥杯大赛个人赛省赛(软件类)真题-Java语言B组

目录

1.ASC

2.卡片

3.直线

4.货物摆放

5.路径

6.时间显示

7.最少砝码

8.杨辉三角形

9.双向排序

10.括号序列


1.ASC

【问题描述】

已知大写字母 A 的 ASCII 码为 65,请问大写字母 L 的 ASCII 码是多少?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

也可直接计算

A

B

C

D

E

F

G

H

I

J

K

L

65

66

67

68

69

70

71

72

73

74

75

76

import java.util.Scanner; 

public class Main{ 
	public static void main(String[] args)throws Exception{ 
		Scanner in = new Scanner(System.in); 
		String b = in.next(); 
		for( int i=0;i< b.length();i++){ 
			System.out.println( b.charAt(i)+" "+(byte) b.charAt(i)); 
		} 
	} 
} 

答案:76

2.卡片

【问题描述】
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 1 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1拼到多少?
提示:建议使用计算机编程解决问题。

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。  

这题求从1开始的连续的数。

toCharArray()该方法的作用是返回一个字符数组,该字符数组中存放了当前字符串中的所有字符。

 估计可能拼出3000多个数,编程打印出1~3500,复制到word文档上

public class Main {
	public static void main(String[] args) {
		for(int i=1;i<=3500;i++)
			System.out.println(i);
	}
}

 

public class Main {
    public static void main(String[] args) {
        int kp[] = new int[10];
        //赋值
        for(int i = 0 ; i <= 9 ; i ++){
            kp[i] = 2021;//每种卡片2021张
        }
        System.out.println(def(kp));
    }
    //判断是否是从1到x的连续的数
    public static int def(int kp[]){
        int i;
        for(i = 1 ; i < 20210 ; i ++){
            int t = i;//防止死循环
            //对每个数去余,余数就是要--的那个下标
            while(t > 0 ){
                kp[t%10]--;
                //只要断片就给他结束
                if(kp[t%10] <= 0 ){
                    return i;
                }
                t /= 10;
            }
        }
        return 0;
    }
}
public class Main {
	public static void main(String[] args) {
		int num = 0;
		//从1开始拼接卡片,明显得出卡片1消耗的最快
		for(int i=1;i<20210;i++) {
			String s=i+"";
//char(int)根据ascii码取得其对应的字符
//​toCharArray()该方法的作用是返回一个字符数组,该字符数组中存放了当前字符串中的所有字符
			char a[]=s.toCharArray();
			for(int j=0;j<a.length;j++) {
				if(a[j]=='1') {
					num++;
				}
			}
			if(num>=2021) {
				System.out.println(i);
				break;
			}
		}
	}
}
public class Main {
	public static void main(String[] args) {
		new Main().run();
	}
	void run() {
		System.out.println(calc(2021));
	}
	int calc(int upper) {
		int[] count = new int[10];
		for(int n=1,k=1; ;k = ++n) {
			do
				if(++count[k%10]>upper)
					return n-1;
			while((k/=10)>0);
		}
	}
}

import java.util.Arrays;

public class Main{
	public static void main(String[] args) {
		int[] hash = new int[10];
		Arrays.fill(hash, 2021);		
		long num = 0;
		boolean flag;
		do {
			num++;
			flag = true;
			char[] str = String.valueOf(num).toCharArray();
			for (char bit : str) {
				if (hash[bit - '0'] > 0) {
					hash[bit - '0']--;
				} else {
					flag = false;
					break;
				}
			}
		} while (flag);		
		System.out.println(num - 1);
	}
}
public class Main {
	public static void main(String[] args) {
		int[] num = new int[10];//我们用长度为10的数组,来模拟数值为0~9的卡片
		int temp;
		int t;
		int i;
		boolean flag = false;
		//每一张都有2021张
		for(i = 0; i < 10; i++) {
			num[i] = 2021;//数值为2的卡片有2021张
		}
		for(i = 1;; i++) {
			temp = i; //用一层从1开始的for循环,来模拟小蓝想知道的:自己能从1拼到多少,由于 i 的值不能随意改变,所以将其值交给 temp 来管理
			
			//想要拼得的数字是12,那么我们就需要一张1,一张2,用过之后我们就不能再用了。
			//整数的拆分。12拆分成1和2,即12 --> 12 % 10 = 2 --> 12 / 10 = 1
			//while循环内部的if语句,它的意思是判断此时想拼的数字是否能拼出来。就比如题目中所提到的11拼不出来的问题
			while(temp != 0) {
				t = temp % 10;
				if(num[t] <= 0) {
					flag = true;
					break;
				}
				num[t]--;
				temp /= 10;
			}
			
			if(flag) {
				break;
			}
		}
		System.out.println(i-1);
	}
}

答案:3181

3.直线

【问题描述】
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上2×3个整点(x,y)0≤x<2.0≤y<3,x∈Zy∈Z),即横坐标是0到1(包含0和1)之间的整数、纵坐标是0到2(包含0和2)之间的整数的点。这些点一共确定了11条不同的直线。
给定平面上20×21个整点(x,y)0≤x<20,0≤y<21,x∈Z,y∈Z),即横坐标是0到19(包含0和19)之间的整数、纵坐标是0到20(包含0和20)之间的整数的点。请问这些点一共确定了多少条不同的直线。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内将无法得分。

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

class Line implements Comparable<Line>{
    double k, b;
    public Line(double kk, double bb){
        this.k = kk;
        this.b = bb;
    }
	@Override
	public int compareTo(Line o) {
		if( Double.compare(this.k, o.k) == 0 ) return Double.compare(this.b, o.b);
		return Double.compare(this.k, o.k);
	}
}
public class Main{
	static int N = 20, M = 21;
//	static int N = 2, M = 3;
	static Line[] q = new Line[1000000];
	static double esp = 10E-8;
	//计算斜率
	public static double getK(int x1, int y1, int x2, int y2) {
		return (double) (y1 - y2) /(x1 - x2) ;
	}
    public static void main(String[] args) {
    	int t = 0;
    	for(int i = 0; i < N; i ++) {
			for(int j = 0; j < M; j ++) {
				//(i, j) --> (x, y)
				for(int x = 0; x < N; x ++) {
					
					if( i == x) continue;
					for(int y = 0; y < M; y ++) {
						if( y == j) continue;
						double k = getK(i, j, x, y);
						double b = j - k * i;
						q[t ++] = new Line(k, b);
					}
				}
			}
		}
		//排序
    	Arrays.sort(q, 0, t);
    	
    	int res = 1; //k :{1,1,2,2,3,3}  {1,2,3}
    	for( int i = 1; i < t; i ++)
    		if( Math.abs(q[i].k - q[i - 1].k ) > esp || Math.abs(q[i].b - q[i - 1].b ) > esp)
    			res ++;
    	System.out.println(res + N + M);
    }
}
import java.util.*;

public class Main {
	static int gcd(int a,int b) {
		return b == 0 ? a:gcd(b,a%b);
	}
	public static void main(String[] args) {
		Set<Integer> set = new HashSet<>();
		Set<String> ans = new HashSet<>();
		int x = 19,y = 20;
		for(int i = 0;i < x;i++) {
			//将坐标以一个四位数的方式存入结合,x是百位和千位,y是十位和百位
			for(int j=0;j<=y;j++) {
				set.add(i*100+j);
			}
		}
		List<Integer> arr = new ArrayList<>(set);
		int len = arr.size();//坐标个数
		for(int i = 0;i < len;i++) {
			int a = arr.get(i);//取出一个坐标
			for(int j = i+1;j < len;j++) {
				int b = arr.get(j);
				int x1 = a/100,x2= b/100,y1 = a%100,y2 = b%100;
				int up = y1-y2,down = x1-x2;
				int c1 = gcd(up,down);//求最大公约数
				String k = (up/c1)+" "+(down/c1);//斜率
				if(down == 0) {
					ans.add("x = " + x1);//如果直线垂直与x轴则直接抛入ans集合,该情况共有19种。
					continue;
				}
				int kb = y1*down - up*x1;
				int c2 = gcd(kb,down);
				String B = (kb/c2)+" "+(down/c2);//截距
				ans.add(k+" "+B);
			}
		}
		System.out.println(ans.size());
	}
}

 【解析】

条件定义:
给定点,求这些点之间不同的直线条数
不同直线定义:在坐标轴中不会重合成一条
构建数据结构表示不同的点:
根据给定数据我们得知x 与 y 都不会超过两位,则我们可以用一个整数表示一个点
即:int point = x * 100 + y;
构建数据结构表示直线:
在坐标轴中确定一条直线有点斜式、斜截式、两点式、截距式,这里我们使用斜截式y = kx + b来表示一条直线,实际上就是k与b确定一条直线,则k = y1- y2 / x1 - x2 , b = y1 - kx1
注意 :我们如果直接这样计算k与b的值来确定一条直线在实际上是不行的(理论可以),因为java 运算时的精度不够导致计算k与b的时候得到大于正确结果的直线数量(使用C/C++的貌似能直接AC)所以采用最简分数(两个整形数据)表示,而最终的一条直线就是由两个分数即四个整形确定,当然对于没有斜率的直线我们直接用横坐标表示。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> points = new ArrayList<>();
        Set<String> ans = new HashSet<>();
        for(int i = 0; i < 20; i ++){
            for (int j = 0; j < 21; j++) {
                points.add(i * 100 + j); //存xy
            }
        }
        int size = points.size();
        for (int i = 0; i < size; i++) {
            int node1 = points.get(i);
            int x1 = node1 / 100, y1 = node1 % 100;
            for (int j = i + 1; j < size; j++) {
                int node2 = points.get(j);
                int x2 = node2 / 100, y2 = node2 % 100;
                int up = y1 - y2, down = x1 - x2;
                if(down == 0){
                    ans.add("x = " + x1);
                    continue;
                }
                int c1 = gcd(up, down);
                String K = up / c1 + " " + down / c1;
                int Up = y1 * down - x1 * up;
                int c2 = gcd(Up, down);
                String B = Up/c2 + " " + down / c2;
                ans.add(K + " " + B);
            }
        }
        System.out.println(ans.size());
    }
    static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}

答案:40257

4.货物摆放

【问题描述】
​ 小蓝有一个超大的仓库,可以摆放很多货物。
​ 现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
​ 小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n = L × W × H。
​ 给定 n,请问有多少种堆放货物的方案满足要求。
​ 例如,当 n = 4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2 × 2 × 1、4 × 1 × 1。
​ 请问,当 n = 2021041820210418 (注意有 16 位数字)时,总共有多少种方案?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内将无法得分。

import java.util.*;

public class Main{
	static long N = 2021041820210418L;
	static List<Long> f = new ArrayList<>();
	public static void main(String[] args) {
		//N=4时,i = 1 2
		//     N/i = 4 2
		for(long i = 1;i * i <= N;i++) {
			if(N%i == 0) {
				f.add(i);
				if(N/i != i)
					f.add(N/i);
			}
		}
		long ans = 0;
		for(long a:f)
			for(long b:f)
				for(long c:f) {
					if(a * b *c ==N)
						ans++;
				}
		System.out.println(ans);
	}
}
public class Main{
	private static final int max = 1010;
	private static long[] a = new long[max];
	public static void main(String[] args) {
		long n = 2021041820210418L;
		int len = 0;
		//找出该数的因子
		for(long i = 1;i * i <=n;i++) {
			if(n%i == 0) {
				a[len++]=i;
				if(i != n/i) {
					a[len++] = n/i;
				}
			}
		}
		long cnt = 0;//堆放方案
		for(int i = 0;i < len;i++) {
			for(int j = 0;j < len;j++) {
				for(int k = 0;k < len;k++) {
					if(a[i] * a[j] * a[k] == n) {//n=L×W×H
						cnt++;
					}
				}
			}
		}
		System.out.println(cnt);
	}
}

答案:2430

5.路径

【问题描述】
    小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
    小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
    对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边相连。
    例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
    请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
    提示:建议使用计算机编程解决问题。

【答案提交】
    这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分

import java.util.Arrays;

public class Main{
	static int N = 2200, M = N *50;//N: 点数 	M:边数
	static int h[] = new int [N];
	static int e[] = new int [M];
	static int w[] = new int [M];
	static int ne[] = new int [M];
	static int idx, n;
	
	static int q[] = new int[N];
	static int dist[] =  new int[N];
	static boolean st[] = new boolean[N];
	 static int INF = 0x3f3f3f3f;
	public static int gcd(int a, int b) {
		return b == 0 ? a : gcd(b, a % b);
	}
	
	public static void add(int a, int b, int c) {//添加一条边a -> b ,边的权重为c
		e[idx] = b;
		w[idx] = c;
		ne[idx]= h[a];
		h[a] = idx ++;
	}
	
	//求1号点到n号点的最短路径
	public static void spfa() {
		int hh = 0, tt = 0;
		Arrays.fill(dist, INF);
		dist[1] = 0;
		q[tt ++] = 1;
		st[1] = true;
		
		while( hh != tt) {
			int t = q[hh ++];
			if( hh == N) hh = 0;
			st[t] = false;
			
			for(int i = h[t]; i != -1; i = ne[i]) {
				int j = e[i];
				if( dist[j] > dist[t] + w[i]) {
					dist[j] = dist[t] + w[i];
					 if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入
		                {
		                    q[tt ++ ] = j;
		                    if (tt == N) tt = 0;
		                    st[j] = true;
		                }
				}
			}
		}
	}
	
	public static void main(String[] args) {
		n = 2021;
		Arrays.fill(h, - 1);
		for(int i = 1; i <= n; i ++) {
			for(int j = Math.max(1, i - 21); j <= Math.min(i + 21, n); j ++) {
				//(i,j)节点
				int d = gcd(i, j);
				add(i, j, i * j / d);
				
			}
		}
		spfa();
		System.out.println(dist[n]);
	}
}

算法思想:
Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)。从任意节点i到任意节点j的最短路径不外乎2种可能,一是直接从i到j,二是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

public class Main {
	static int[][] graph = new int[2022][2022];
	static final int INF = 0x3f3f3f3f;//这个数表示无穷大
	private static void floyd() {
		for (int k = 1;k <= 2021;k++) {
			for(int i = 1;i <= 2021;i++) {
				for(int j = 1;j <= 2021;j++) {
					if(i != j && graph[i][j] > graph[i][k] + graph[k][j]) {
						graph[i][j] = graph[i][k] + graph[k][j];
					}
				}
			}
		}
	}
	private static int gcd(int a,int b) {
		return b == 0 ? a : gcd(b,a%b);
	}
	public static void main(String[] args) {
		for(int i = 1;i <= 2021;i++) {
			for(int j = 1;j <= 2021;j++) {
				graph[i][j] = INF;
			}
		}
		for(int i = 1;i <= 2021;i++) {
			int st = Math.max(i - 21, 1);//这么写是因为差值<=21的点之间才有直接相连的边
			for(int j = st;j <= i;j++) {
				int div = gcd(j,i);
				int lcm = i * j / div;//无向边的大小
				graph[i][j] = lcm;
				graph[j][i] = lcm;
			}
		}
		floyd();
		System.out.println(graph[1][2021]);
	}
}

答案:10266837

6.时间显示

【问题描述】

小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970  年 1 月 1 日 00 : 00 : 00  到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

【输入格式】

输入一行包含一个整数,表示时间。

【输出格式】

输出时分秒表示的当前时间,格式形如 H H : M M : S S,其中 H H表示时,值为 0  到 23 ,M M  表示分,值为 0 到 59,S S  表示秒,值为 0  到 59 。时、分、秒不足两位时补前导 0。

【样例输入1】

46800999

【样例输出1】

13:00:00
【样例输入2】

1618708103123

【样例输出2】

01:08:23 

import java.util.Scanner;
 
public class Main {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		long n=sc.nextLong();
		n/=1000;//得出秒
		int day=24*60*60;//一小时的秒数
		n=n%day;//求出时的秒数
		int h=(int) (n/(60*60));//一分钟的秒数
		n%=60*60;//求出分的秒数
		int m=(int) (n/60);//一的秒数
		n%=60;//求出秒的秒数
		String date;
		if(h>10) {
			date=h+":";	
		}else {
			date="0"+h+":";	
		}
		if(m>10) {
			date+=m+":";	
		}else {
			date+="0"+m+":";	
		}
		if(n>10) {
			System.out.println(date+n);	
		}else {
			System.out.println(date+"0"+n);
		}				
	}
}
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long n = sc.nextLong();
		n -= 8*60*60*1000;
		Date date = new Date(n);
		SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
		System.out.println(format.format(date));
	}
}

 【注意】

用Date时要注意时区问题,我们是东8区所已一开始是1900-01-01 8:00:00

所有要减去8个小时的毫秒数。

import java.util.*;

public class Main {
    public static void main(String[] args) {
    	Scanner scanner=new Scanner(System.in);
    	long nub=scanner.nextLong();
    	nub/=1000;
    	long hours=nub/60/60%60;
    	String hoursString=String.valueOf(hours);
    	long minute=nub/60%60;
    	String minuteString=String.valueOf(minute);
    	long second=nub%60;
    	String secondString=String.valueOf(second);
    	if (hours<10) {
			 hoursString="0"+hours;
		}
    	if (minute<10) {
			 minuteString="0"+minute;
		}
    	if (second<10) {
			 secondString="0"+second;
		}
    	System.out.println(hoursString+":"+minuteString+":"+secondString);
    }
}

7.最少砝码(等比数列)

【问题描述】
   你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意小于等于 N 的正整数重量。
   那么这套砝码最少需要包含多少个砝码?
   注意砝码可以放在天平两边。

【输入格式】
输入包含一个正整数 N。

【输出格式】
输出一个整数代表答案。

【样例输入】
7

【样例输出】
3

【样例说明】
3 个砝码重量是 1、4、6,可以称出 1 至 7 的所有重量。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少于 3 个砝码不可能称出 1 至 7 的所有重量。

结果应该是最少的砝码数量
首先,如果要称的重量为1的话,只能选择重量为1的砝码,1是必选的一个砝码。

然后再称比1重的,反正都是要再加砝码,那我们为何不选一个能称的重量尽可能大的呢。
选1、2的砝码可以满足1=1,2=2,3=1+2
选1、3的砝码可以满足1=1,2=3-1,3=3,4=3+1
选1、4的砝码可以满足1=1,2=?无法称2,不合题意
因此我们选择的砝码组合是1、3,此时我们可以称的最大重量为4

当我们还需要再增加砝码时
同理可得
选1、3、9的组合可以满足小于等于13(13=1+3+9)的所有重量

从中可以发现一个规律,当我们需要第三个砝码是,前两个砝码(1、3)满足的最大重量已经是4了,下一个要满足的重量是5,我们遵循砝码尽可能大的原则,选择的第三个砝码的重量满足的条件是:它减去 已经可以称得的最大重量 可以得到 下一个需要称的重量。也就是weight - 4 = 5,可得weight为9

再往下推,可以得到下面的表格

砝码序号砝码重量总重量(可称出的最大重量)
111
234
3913
42740
count=count+1weight=weight*3total=total+weight

count=count+1    weight=weight*3    total=total+weight
到此已经找到规律,可以写出这道题的代码了
表格的三列分别对应了

count++;		//count=count+1
weight*=3;		//weight=weight*3
total+=weight;	//total=total+weight

其中总重量是当前所有砝码之和,因此必须先乘3,后加到总重量里,除此之外,三行代码的顺序可调换

如果想证明的话,可以发现,取第三个砝码是weight - 4 = 5,要求的下一个重量5是总重量+1,即下一个砝码重量是当前总重量*2+1,nextWeight = total * 2+1,也可以表示为要求的下一个砝码重量weight=previousTotal * 2 + 1
证明第count次增加的砝码都是3的count-1次方

当count=1时,砝码只有一个,重量为1, 3 的count−1次方 =1

当count=2时,砝码组合为1、3,是首项为1,公比为3的等比数列

设count=k(k>=2)时,砝码组合是一个首项为1公比为3等比数列,末项为3的count−1次方
 ,则total=(3的count次方−1) /2 

则当count=k+1时,第k+1个砝码的重量 weight = previousTotal * 2+1 = (3的count次方−1) /2 *2+1=3的count次方
 ,此时砝码组合是一个首项为1,公比为3的等比数列,末项为3的count次方

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		sc.close();
		int weight = 1,count = 1,total = 1;
		while(total < n) {
			count++;//count=count+1
			weight *= 3;//weight=weight*3
			total += weight;//total=total+weight
		}
		System.out.println(count);
	}
}

8.杨辉三角形

【问题描述】
下面的图形是著名的杨辉三角形:

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, …
给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?
【输入格式】
输入一个整数 N。
【输出格式】
输出一个整数代表答案。
【样例输入】
6
【样例输出】
13
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ N ≤ 10;
对于所有评测用例,1 ≤ N ≤ 1000000000。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    	new Main().run();
    }
    int N;
    private void run() {
    	Scanner sc = new Scanner(System.in);
    	int N =  sc.nextInt();
    	if(N == 1)
    		System.out.println(1);
    	else {
    		long ans = (N + 1L) * N / 2 + 2;
    		for(int m = 2;m < 16;m++) {
    			int start = m * 2,end = N;
    			while(start <= end) {
    				int mid = start + end >> 1;
    				if(C(mid,m) == N) {
    					ans = min(ans,(mid + 1L) * mid / 2 + m +1);
    					break;
    				}if (C(mid,m) > N)
    					end = mid - 1;
    				else
    					start = mid + 1;
    			}
    		}
    		System.out.println(ans);
    		}
    	}
    long min(long a,long b) {
    	return a < b ? a : b;
    }
    long C(int n,int m) {
    	long num = 1;
    	for(int nm = 1;nm <= m;n--,nm++)
    		if((num = num * n /nm) > N)
    			return num;
    	return num;
    }
}

9.双向排序

【问题描述】

给定序列 (a_1, a_2, · · · , a_n) = (1, 2, · · · , n),即 a_i =i。

小蓝将对这个序列进行 m 次操作,每次可能是将 a_1, a_2,... , a_qi降序排列,或者将a_qi​​,a_qi+1​​,⋯,a_n​ 升序排列。

请求出操作完成后的序列。

【输入格式】

输入的第一行包含两个整数 n,m​,分别表示序列的长度和操作次数。

接下来 m 行描述对序列的操作,其中第 i 行包含两个整数 p_i, q_i 表示操作类型和参数。当 p_i = 0时,表示将 a_1, a_2, ⋅⋅⋅,a_qi​​​​ 降序排列;当 p_i = 1时,表示将 a_qi , a_qi+1, ..., a_n​​ 升序排列。

【输出格式】

输出一行,包含 n 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。

【样例输入】

3 3
0 3
1 2
0 2

【样例输出】 

3 1 2

【样例说明】

原数列为 (1, 2, 3)​​​​​。

第 11​​​​​ 步后为 (3, 2, 1)​​​​​。

第 22​​​​ 步后为 (3, 1, 2)​​。

第 33​​​ 步后为 (3, 1, 2)。与第 22 步操作后相同,因为前两个数已经是降序了。

【评测用例规模与约定】

对于 30% 的评测用例,n,m≤1000;

对于 60% 的评测用例,n,m≤5000;

对于所有评测用例,1≤n,m≤100000,0≤p_i​≤1,1≤q_i​≤n。

import java.util.*;

public class Main {
	static int N = 100010;
	static CII stk[] = new CII[N];
	static int a[] = new int [N];
	static int top;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();//序列的长度
		int m = sc.nextInt();//操作次数
		
		while(m-- > 0) {
			int t = sc.nextInt();
			int x = sc.nextInt();
			if(t == 0) {
				while(top > 0 && stk[top].t ==0)
					x = Math.max(x, stk[top --].x);
				while(top >= 2 && stk[top-1].x <= x)
					top -=2;
				stk[++top] = new CII(0,x);
			}
		else if(top != 0) {
			while(stk[top].t == 1)
				x = Math.min(x, stk[top--].x);
			while(top >= 2 && stk[top-1].x >= x)
				top -=2;
			stk[++top] = new CII(1,x);
		}
	}
	
	int l = 1,r = n,k = n;
	for(int i = 1;i <= top;i++) {
		int x = stk[i].x;
		if(stk[i].t == 0) {
			while(r > x && l <= r)
				a[r--] = k--;
		}else {
			while(l < x && l <= r)
				a[l++] = k--;
		}
		if(l > r)
			break;
	}
	if(top % 2 == 1)
		while(l <= r)
			a[l++] = k--;
	else
		while(l <= r)
			a[r--] = k--;
	for(int i = 1;i <= n;i++)
		System.out.println(a[i] + " ");
	}
	static class CII{
		int t,x;
		public CII(int a,int b) {
			t = a;
			x = b;
		}
	}
}

10.括号序列

【问题描述】

给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果,请问有多少种本质不同的添加结果。

两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。

例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。

【输入格式】
输入一行包含一个字符串 s,表示给定的括号序列,序列中只有左括号和右括号。

【输出格式】
输出一个整数表示答案,答案可能很大,请输出答案除以 1000000007 (即 10^9+7) 的余数。

【样例输入】

((()

【样例输出】

5

【评价用例规模与约定】
对于 40% 的评测用例,|s|≤200。 对于所有评测用例,1≤|s|≤5000。

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main{
    static Set<String> set = new HashSet<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int left = 0;
        int right = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
        }
        //int count = Math.max(left, right);
        int count;//最多的括号数量
        int sub;//插入的括号不能超过sub个,也就是不一样的括号数量
        if (left > right) {
            count = left;
            sub = left - right;
        } else {
            count = right;
            sub = right - left;
        }

        String temp = "";
        for (int i = 0; i < count; i++) {
            temp += "()";
        }
        dfs(temp);

        int resCount = 0;

        for (String s1 : set) {
            int i = 0;
            int j = 0;
            boolean isMatch = true;
            while (i < s.length() && j < s1.length()) {
                int tempCount = sub;
                if (s.charAt(i) == s1.charAt(j)) {
                    i++;
                    j++;
                } else {
                    j++;
                    tempCount--;
                }
                if (tempCount < 0) {
                    isMatch = false;
                    break;
                }
            }
            if (isMatch) {
                resCount++;
            }
        }

        System.out.println(resCount);
    }

    private static void dfs(String temp) {
        set.add(temp);
        for (int i = 0; i < temp.length() - 1; i++) {
            if (temp.charAt(i) == ')' && temp.charAt(i + 1) == '(') {
                String temps = temp.substring(0, i) + "()" + temp.substring(i + 2, temp.length());
                dfs(temps);
            }
        }
    }
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一条小橘猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值