进制均值
题目描述
尽管是一个CS专业的学生,小B的数学基础很好并对数值计算有着特别的兴趣,喜欢用计算机程序来解决数学问题,现在,她正在玩一个数值变换的游戏。她发现计算机中经常用不同的进制表示一个数,如十进制数123表达为16进制时只包含两位数7、11(B),用八进制表示为三位数1、7、3,按不同进制表达时,各个位数的和也不同,如上述例子中十六进制和八进制中各位数的和分别是18和11,。 小B感兴趣的是,一个数A如果按2到A-1进制表达时,各个位数之和的均值是多少?她希望你能帮她解决这个问题? 所有的计算均基于十进制进行,结果也用十进制表示为不可约简的分数形式。
输入描述:
输入中有多组测试数据,每组测试数据为一个整数A(1 ≤ A ≤ 5000).
输出描述:
对每组测试数据,在单独的行中以X/Y的形式输出结果。
输入例子1:
5
3
输出例子1:
7/3
2/1
思路
主要需要解决两个问题:
- 十进制转其他进制
//求某一进制下各位和
public static int fun(int num,int base){
int sum = 0;
while(num != 0){
sum += num % base;
num = num / base;
}
return sum;
}
- 最终得到的结果是分数,需要约分(即求分母,分子的最大公约数)
//对分数约分
public static int gcd(int one, int two){
return two == 0 ? one : gcd(two, one % two);
}
完整实现
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int sum=0;
//输入个数未知
while(sc.hasNext()){
int A=sc.nextInt();
//每一个分别调用函数
for(int i=2;i<A;i++){
sum+=fun(A,i);
}
int gcd=gcd(sum,A-2);
System.out.println(sum/gcd+"/"+(A-2)/gcd);
}
}
//求某一进制下各位和
public static int fun(int num,int base){
int sum = 0;
while(num != 0){
sum += num % base;
num = num / base;
}
return sum;
}
//对分数约分
public static int gcd(int one, int two){
return two == 0 ? one : gcd(two, one % two);
}
}
幸运数
题目描述
小明同学学习了不同的进制之后,拿起了一些数字做起了游戏。小明同学知道,在日常生活中我们最常用的是十进制数,而在计算机中,二进制数也很常用。现在对于一个数字x,小明同学定义出了两个函数f(x)和g(x)。 f(x)表示把x这个数用十进制写出后各个数位上的数字之和。如f(123)=1+2+3=6。 g(x)表示把x这个数用二进制写出后各个数位上的数字之和。如123的二进制表示为1111011,那么,g(123)=1+1+1+1+0+1+1=6。 小明同学发现对于一些正整数x满足f(x)=g(x),他把这种数称为幸运数,现在他想知道,大于0且小于等于n的幸运数有多少个?
思路
进制转换,思路很简单
完整实现
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int cnt=0;
for(int i=1;i<=n;i++){
if(f(i)==g(i)){
cnt++;
}
}
System.out.println(cnt);
}
public static int f(int x){
int sum=0;
while(x!=0){
sum+=(x%10);
x=x/10;
}
return sum;
}
public static int g(int x){
int sum=0;
while(x!=0){
sum+=(x%2);
x=x/2;
}
return sum;
}
}
集合
题目描述
给你两个集合,要求{A} + {B}。 注:同一个集合中不会有两个相同的元素。
思路
需要实现两个任务:合并(不允许重复)+排序
所以使用TreeSet来存储合并后的元素
还有一点需要注意的是输出结果要以空格隔开,但是最后一个元素后面没有空格,所以把输出结果转换成字符串,遍历TreeSet集合,每个元素输出后都在后面加一个空格。
最终输出时截取子串,去掉最后一个空格
完整实现
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int m=sc.nextInt();
int n=sc.nextInt();
int[] M=new int[m];
int[] N=new int[n];
for(int i=0;i<m;i++){
M[i]=sc.nextInt();
}
for(int i=0;i<n;i++){
N[i]=sc.nextInt();
}
TreeSet<Integer> set=new TreeSet<>();
for(int i=0;i<m;i++){
set.add(M[i]);
}
for(int i=0;i<n;i++){
set.add(N[i]);
}
String s="";
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()){
String str=String.valueOf(iterator.next());
s+=str+" ";
}
System.out.println(s.substring(0,s.length()-1));
}
}
括号匹配
题目描述
合法的括号匹配序列被定义为:
- 空串""是合法的括号序列
- 如果"X"和"Y"是合法的序列,那么"XY"也是一个合法的括号序列
- 如果"X"是一个合法的序列,那么"(X)"也是一个合法的括号序列
- 每个合法的括号序列都可以由上面的规则生成
例如"", “()”, “()()()”, “(()())”, "(((())))"都是合法的。 东东现在有一个合法的括号序列s,一次移除操作分为两步: - 移除序列s中第一个左括号
- 移除序列s中任意一个右括号.保证操作之后s还是一个合法的括号序列
东东现在想知道使用上述的移除操作有多少种方案可以把序列s变为空
如果两个方案中有一次移除操作移除的是不同的右括号就认为是不同的方案。
例如: s = “()()()()()”,输出1, 因为每次都只能选择被移除的左括号所相邻的右括号.
s = “(((())))”,输出24, 第一次有4种情况, 第二次有3种情况, … ,依次类推, 4 * 3 * 2 * 1 = 24
思路
以 ((()))(()) 为例
可以看出可以分为两个连续序列,前一个方案数为3!,后一个方案数为2!,再将二者相乘得到最终方案数
我们可以使用一个tmp(可以理解为指针)来遍历序列,tmp初始为0:
- 当遇到的是’(’,就一直向前遍历,即tmp++,直到遇到第一个’)’,此时tmp=第一个连续括号序列的左括号数
- 当遇到’)'后,就可以开始计算方案数,即tmp的阶乘。
同时,要进行tmp–操作,使tmp重新回到0,就可以开始下一个连续括号序列的遍历了
完整实现
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
String s=sc.next();
//相当于把不连续的括号序列分开
int num=1; //方案数
int tmp=0; //tmp表示每个连续括号序列的开端
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
tmp++;
}
else{
num=num*tmp;
tmp--;
}
}
System.out.println(num);
}
}