训练(二)

目录

数字三角形

排序

棋盘放麦子

成绩分析

饮料换购

门牌制作

质数

         明码


数字三角形

    7
   3 8
  8 1 0
 2 7 4 4
4 5 2 6 5

上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。

路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。

输入:
第一行为三角形行数,下面的 N 行给出数字三角形。
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出:
27

因为向左走的次数与向右走的次数差值不能超过1,所以到达最后一层时,一定是落在中间位置。如果层数是奇数,那么最后一定落在最后一层的第n/2+1个元素上,如果层数是偶数,最后一定是落在第n/2或第n/2+1个元素上。所以只要从最后一层的中间开始向上递推就可以了。

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {

    public static void main(String[] args) {
        // 处理输入
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int [][] a = new int[105][105];
        int [][] dp = new int[105][105];
        //输入三角形
        for (int i=1;i<=n;i++) 
        {
            for (int j=1;j<=i;j++) 
            {
                a[i][j] = scan.nextInt();
            }
        }
        //准备递推
        if(n%2==0)
        {
        	dp[n][n/2] = a[n][n/2];
        	dp[n][n/2+1] = a[n][n/2+1];
        }
        else
        {
        	dp[n][n/2+1] = a[n][n/2+1];
        }
        //开始递推
        for(int i=n-1;i>=1;i--)
        {
        	for(int j=1;j<=i;j++)
        	{
        		if(dp[i+1][j]!=0 || dp[i+1][j+1]!=0)
        		{
        			dp[i][j] = a[i][j] + Math.max(dp[i+1][j], dp[i+1][j+1]);
        		}
        	}
        }
        System.out.println(dp[1][1]);
        scan.close();
    }
}

排序

小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。

在冒泡排序中,每次只能交换相邻的两个元素。

小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符, 则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。

例如,对于字符串 lanlan 排序,只需要 11 次交换。对于字符串 qiaoqiao 排序,总共需要 44 次交换。

小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要 100100 次交 换,可是他忘了吧这个字符串记下来,现在找不到了。

请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对 该串的字符排序,正好需要 100100 次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。

解析

1、对于拥有N个字母的字符串,最坏情况需要交换N*(N-1)/2次(完全逆序)。
2、易知N=15时,有15*14/2=105次,即满足100次交换所需的最短字符串有15个字母。
3、要求字典序最小,显然要取a~o这15个字母。
4、逆向思考,目标字符串经过100次交换后,得到正序字符串abcdefghijklmno。
而完全逆序的字符串onmlkjihgfedcba变成正序字符串需要105次交换,那么将完全逆序的字符串交换5次后,便能得到答案。
5、将j交换5次提到字符串最前面,就得到了字典序最小的情况。

答案

jonmlkihgfedcba


棋盘放麦子

在第 1 个棋盘格放 1 粒麦子,在第 2 个棋盘格放 2 粒麦子,在第 3 个棋盘格放 4 粒麦子,在第 4 个棋盘格放 8 粒麦子,......后一格的数字是前一格的两倍,直到放完所有棋盘格(国际象棋共有 64 格)。

请你借助计算机准确地计算,到底需要多少粒麦子。

import java.math.BigInteger;
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {

    public static void main(String[] args) {
        // 处理输入
        Scanner scan = new Scanner(System.in);
        BigInteger sum=BigInteger.valueOf(1);
        BigInteger wheat=BigInteger.valueOf(1);
        BigInteger two=BigInteger.valueOf(2);
        for(int i=2;i<=64;i++)
        {
        	wheat=wheat.multiply(two);
        	sum=sum.add(wheat);
        }
        System.out.println(sum);
        scan.close();

    }
}

成绩分析

输入n+1行

第一行包含一个整数 n (1 ≤ n ≤ 10^4),表示考试人数。

接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。

输出三行。

第一行包含一个整数,表示最高分。

第二行包含一个整数,表示最低分。

第三行包含一个实数,四舍五入保留正好两位小数,表示平均分。

题目不难,注意平均分的处理即可。

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {

    public static void main(String[] args) {
        // 处理输入
        Scanner scan = new Scanner(System.in);
        int n=scan.nextInt();
        int max=0;
        int min=100;
        int sum=0;
        for(int i=0;i<n;i++)
        {
        	int s=scan.nextInt();
        	if(s>max)
        	{
        		max=s;
        	}
        	if(s<min)
        	{
        		min=s;
        	}
        	sum+=s;
        }
        double avg=(double)sum/n;
        System.out.println(max);
        System.out.println(min);
        System.out.printf("%.2f",avg);
        scan.close();

    }
}

饮料换购

凭 3 个瓶盖可以再换一瓶 C 型饮料,并且可以一直循环下去(但不允许暂借或赊账)。

请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的 n 瓶饮料,最后他一共能喝到多少瓶饮料。

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {

    public static void main(String[] args) {
        // 处理输入
        Scanner scan = new Scanner(System.in);
        int n=scan.nextInt();
        for(int i=3;i<=n;i+=3)
        {
        	n++;
        }
        System.out.println(n);
        scan.close();

    }
}

门牌制作

请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {

    public static void main(String[] args) {
        // 处理输入
        Scanner scan = new Scanner(System.in);
        int cnt=0;
        for(int i=1;i<=2020;i++)
        {
        	int temp=i;
        	while(temp!=0)
        	{
        		if(temp%10==2)
        		{
        			cnt++;
        		}
        		temp/=10;
        	}
        }
        System.out.println(cnt);
        scan.close();

    }
}

质数

我们知道第一个质数是 2、第二个质数是 3、第三个质数是 5……第 2019 个质数是多少?

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {

    public static void main(String[] args) {
        // 处理输入
        Scanner scan = new Scanner(System.in);
        int cnt=0;
        for(int i=2;i<99999999;i++)
        {
        	for(int j=2;j<=i;j++)
        	{
        		if(i%j==0 && i!=j)
        		{
        			break;
        		}
        	    else if(i%j==0 && i==j)
        		{
        			cnt++;
        			if(cnt==2019)
        			{
        				System.out.println(i);
        			}
        		}
        	}
        }
        scan.close();
    }
}

明码

汉字的字形存在于字库中,即便在今天,16 点阵的字库也仍然使用广泛。

16 点阵的字库把每个汉字看成是16×16 个像素信息。并把这些信息记录在字节中。

一个字节可以存储 88 位信息,用 32 个字节就可以存一个汉字的字形了。 把每个字节转为 2 进制表示,1 表示墨迹,0 表示底色。每行 2 个字节,一共 16 行,布局是:

    第 1 字节,第 2 字节
    第 3 字节,第 4 字节
    ....
    第 31 字节, 第 32 字节

这道题目是给你一段多个汉字组成的信息,每个汉字用 3232 个字节表示,这里给出了字节作为有符号整数的值。

题目的要求隐藏在这些信息中。你的任务是复原这些汉字的字形,从中看出题目的要求,并根据要求填写答案。

这段信息是(一共 1010 个汉字):

4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0 
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16 
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0 
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4 
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64 
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128 
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0 
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0 
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0 
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0 

代码 

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
	
	//十进制->二进制:除二倒取余
	public static String toBinary(int b)
	{
		String bin="";
		//一个字节存储8位信息:十进制->8位二进制
		//为方便观察,1->*,0-> (空格)
		for(int i=0;i<8;i++)
		{
			if(b<0)
			{
				b=-b+1;
			}
			if(b%2==0)
			{
				bin+=" ";   
			}
			else
			{
				bin+="*";
			}
			b/=2;
		}
		//使用StringBuffer将整个字符串倒过来
		StringBuffer sb =new StringBuffer(bin);
		return sb.reverse().toString();
	}
	
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        
        //存储字节,共十行,每行32个字节
        int[][] by=new int[15][40];    
        for(int i=0;i<10;i++)
        {
        	for(int j=0;j<32;j++)
        	{
        		by[i][j]=scan.nextInt();
        	}
        }
        
        //输出明码
        for(int i=0;i<10;i++)
        {
        	for(int j=0;j<32;j++)
        	{
        		System.out.print(toBinary(by[i][j]));
        		//一行2个字节 && 下标从0开始:01换行 , 23换行……  即如果行数%2!=0,换行
        		if(j%2!=0)
        		{
        			System.out.println();
        		}
        	}
        }
        
        scan.close();
    }
}

这样写实际上是有误的,因为没有考虑到负数的情况。

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
	
	//十进制->二进制:除二倒取余
	public static String toBinary(int b)
	{
		String bin=Integer.toBinaryString(b);
		
		//一个字节存储8位信息:十进制->8位二进制
		//Integer.toBinaryString(8)
		//00000000 00000000 00000000 00001000,高位的0被省略,得到1000,需要在前面补足0
		//Integer.toBinaryString(-8) 就是在上述基础上取反加一
		//11111111 11111111 11111111 11111000,需要将高位1截去
		
		if(b<0)  
		{
			bin=bin.substring(24);  //从24位开始截取,即截出后8位
		}
		else
		{
			while(bin.length()<8)
			{
				bin="0"+bin;
			}
		}

		//为方便观察,1->*,0-> (空格)
		//通过StringBuilder类来操作字符串
		StringBuilder sb=new StringBuilder(bin);
		for(int i=0;i<sb.length();i++)
		{
			if(sb.charAt(i)=='1')
			{
				sb.setCharAt(i, '*');
			}
			else
			{
				sb.setCharAt(i, ' ');
			}
		}
		return sb.toString();
	}
	
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        
        //存储字节,共十行,每行32个字节
        int[][] by=new int[15][40];    
        for(int i=0;i<10;i++)
        {
        	for(int j=0;j<32;j++)
        	{
        		by[i][j]=scan.nextInt();
        	}
        }
        
        //输出明码
        for(int i=0;i<10;i++)
        {
        	for(int j=0;j<32;j++)
        	{
        		System.out.print(toBinary(by[i][j]));
        		//一行2个字节 && 下标从0开始:01换行 , 23换行……  即如果行数%2!=0,换行
        		if(j%2!=0)
        		{
        			System.out.println();
        		}
        	}
        }
        
        scan.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值