PREV55 小计算器
题目描述
问题描述
模拟程序型计算器,依次输入指令,可能包含的指令有
1. 数字:'NUM X',X为一个只包含大写字母和数字的字符串,表示一个当前进制的数
2. 运算指令:'ADD','SUB','MUL','DIV','MOD',分别表示加减乘,除法取商,除法取余
3. 进制转换指令:'CHANGE K',将当前进制转换为K进制(2≤K≤36)
4. 输出指令:'EQUAL',以当前进制输出结果
5. 重置指令:'CLEAR',清除当前数字
指令按照以下规则给出:
数字,运算指令不会连续给出,进制转换指令,输出指令,重置指令有可能连续给出
运算指令后出现的第一个数字,表示参与运算的数字。且在该运算指令和该数字中间不会出现运算指令和输出指令
重置指令后出现的第一个数字,表示基础值。且在重置指令和第一个数字中间不会出现运算指令和输出指令
进制转换指令可能出现在任何地方
运算过程中中间变量均为非负整数,且小于2^63。
以大写的'A''Z'表示1035
输入格式
第1行:1个n,表示指令数量
第2..n+1行:每行给出一条指令。指令序列一定以'CLEAR'作为开始,并且满足指令规则
输出格式
依次给出每一次'EQUAL'得到的结果
样例输入
7
CLEAR
NUM 1024
CHANGE 2
ADD
NUM 100000
CHANGE 8
EQUAL
样例输出
2040
算法分析
这里主要用到的核心语法是
- 1、
10
进制转r进制Integer.toString(int x,int r)
将10
进制的x
转化为r
进制,并返回字符串,若x
过大,可以写成Long.toString(int x,int r)
- 2、
r
进制转10
进制Integer.parseInt(String s,int r)
将r
进制的s
转化为10
进制,并返回一个数字类型,若返回值过大,可以写成Long.parseLong(String s,int r)
注意: -
10
进制转r
进制,若有字母,转出来的是小写 -
r
进制转10
进制,无论x
里面包含小写还是大写,出来的数字都是一样的
public class Main {
//10进制转r进制
static String ten_to_r(long x,int r)
{
return Long.toString(x,r);
}
//r进制转10进制
static long r_to_ten(String s,int r)
{
return Long.parseLong(s,r);
}
public static void main(String[] args){
System.out.println(ten_to_r(1000,11)); // 答案:82a
System.out.println(r_to_ten("82A",11));// 答案:1000
System.out.println(r_to_ten("82a",11));// 答案:1000
}
}
模拟
ans
记录的是当前10
进制的结果(统一记录成10
进制),op
代表当前的操作数,r
表示当前数的进制,输出的时候再从10
进制转化为当前进制数
时间复杂度
不清楚
Java 代码
import java.util.Scanner;
public class Main {
static long ans = -1;//永远记录10进制的答案
static String op = "#";
static int r = 10;
//10进制转r进制
static String ten_to_r(long x,int r)
{
return Long.toString(x,r);
}
//r进制转10进制
static long r_to_ten(String s,int r)
{
return Long.parseLong(s,r);
}
//ans通过op操作更新答案
static void update_ans(String op,String x)
{
long t = r_to_ten(x,r);//将x变为10进制
if(op.equals("ADD"))
{
ans += t;
}
else if(op.equals("SUB"))
{
ans -= t;
}
else if(op.equals("MUL"))
{
ans *= t;
}
else if(op.equals("DIV"))
{
ans /= t;
}
else if(op.equals("MOD"))
{
ans %= t;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
while(n -- > 0)
{
String t = scan.next();
if(t.equals("CLEAR"))
{
ans = -1;
}
else if(t.equals("NUM"))
{
String x = scan.next();
if(ans == -1) ans = r_to_ten(x,r);
else update_ans(op,x);
}
else if(t.equals("CHANGE"))
{
r = Integer.parseInt(scan.next());
}
else if(t.equals("ADD"))
{
op = "ADD";
}
else if(t.equals("SUB"))
{
op = "SUB";
}
else if(t.equals("MUL"))
{
op = "MUL";
}
else if(t.equals("DIV"))
{
op = "DIV";
}
else if(t.equals("MOD"))
{
op = "MOD";
}
else
{
String temp = ten_to_r(ans,r);
for(int i = 0;i < temp.length();i ++)
{
if(temp.charAt(i) >= 'a' && temp.charAt(i) <= 'z')
System.out.print((char)(temp.charAt(i) - ('a' - 'A')));
else System.out.print(temp.charAt(i));
}
System.out.println();
}
}
}
}
PREV54 合根植物
题目描述
资源限制
时间限制:2.0s 内存限制:256.0MB
问题描述
w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
输入格式
第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1
格子的编号一行一行,从上到下,从左到右编号。
比如:5 * 4 的小格子,编号:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
样例输入
5 4
16
2 3
1 5
5 9
4 8
7 8
9 10
10 11
11 12
10 14
12 16
14 18
17 18
15 19
19 20
9 13
13 17
样例输出
5
算法分析
并查集
将所有能连通的点合并到一个集合,求集合的个数,从1
枚举到n * m
,将所有点对应的集合根结点放进set
中进行判重,输出set
的大小即可
时间复杂度
并查集操作接近O(1)
Java 代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
public class Main {
static int N = 1000010;
static int n,m;
static int[] p = new int[N];
static Set set = new HashSet();
static int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s1 = br.readLine().split(" ");
n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
int k = Integer.parseInt(br.readLine());
for(int i = 1;i <= n * m;i ++) p[i] = i;
while(k -- > 0)
{
String[] s2 = br.readLine().split(" ");
int a = Integer.parseInt(s2[0]);
int b = Integer.parseInt(s2[1]);
a = find(a);
b = find(b);
p[a] = b;
}
for(int i = 1;i <= n * m;i ++) set.add(find(i));
System.out.println(set.size());
}
}
PREV53 分考场
题目描述
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
输入格式
第一行,一个整数n(1
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
输出格式
一行一个整数,表示最少分几个考场。
样例输入
5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
4
样例输入
5
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5
算法分析
经验:在蓝桥杯中,如果数据范围是100,用爆搜 + 各种剪枝还是可以通过的
此题没有什么思路,可以只用dfs做
dfs(int x,int nums)
表示当前枚举到底x
个人,nums
表示目前开了多少个考场
g[i][j]
数组记录的是第i
个人是否和第j
个人认识
dfs
的过程,依次枚举所有的人往现有的nums
考场上放,枚举所有情况
第x
个人往第1
个考场放
第x
个人往第2
个考场放
...
第x
个人往第nums
个考场放
新开一个考场,第x
个人往第nums + 1
个考场放
优化:
最优性剪枝:若当前考场数量比ans
大,则退出
可行性剪枝,若当前考场有当前这个人x
认识的,则continue
时间复杂度
具有剪枝,不好分析
Java 代码
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
static int N = 110;
static int n,m;
static boolean[][] g = new boolean[N][N];
static LinkedList[] list = new LinkedList[N];
static int ans = Integer.MAX_VALUE;
static boolean check(int x,int u)
{
for(int i = 0;i < list[u].size();i ++)
{
int t = (int)list[u].get(i);
if(g[x][t]) return false;
}
return true;
}
static void dfs(int x,int nums)
{
if(nums >= ans) return; //最优性剪枝
if(x == n + 1)
{
ans = Math.min(ans, nums);
return;
}
//能否放在本来有的考场
for(int i = 1;i <= nums;i ++)
{
if(!check(x,i)) continue;
list[i].add(x);
dfs(x + 1,nums);
list[i].remove(list[i].size() - 1);
}
//新开一个
list[nums + 1].add(x);
dfs(x + 1,nums + 1);
list[nums + 1].remove(list[nums + 1].size() - 1);
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
m = scan.nextInt();
while(m -- > 0)
{
int a = scan.nextInt();
int b = scan.nextInt();
g[a][b] = g[b][a] = true;
}
for(int i = 1;i <= n;i ++) list[i] = new LinkedList();
dfs(1,0);
System.out.println(ans);
}
}
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。
本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。
输入格式
一行三个整数:a b n,用空格分开。a是被除数,b是除数,n是所求的小数后位置(0 输出格式
一行3位数字,表示:a除以b,小数后第n位开始的3位数字。
样例输入
1 8 1
样例输出
125
样例输入
1 8 3
样例输出
500
样例输入
282866 999000 6
样例输出
914
Java代码
PREV52 小数第n位
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。
本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。
输入格式
一行三个整数:a b n,用空格分开。a是被除数,b是除数,n是所求的小数后位置(0 输出格式
一行3位数字,表示:a除以b,小数后第n位开始的3位数字。
样例输入
1 8 1
样例输出
125
样例输入
1 8 3
样例输出
500
样例输入
282866 999000 6
样例输出
914
算法分析
这里主要的公式可以列出来
用快速幂求,时间复杂度
时间复杂度
Java 代码
import java.util.Scanner;
public class Main {
static long qmi(int a,int k,int p)
{
long res = 1 % p;
long t = a;
while(k > 0)
{
if((k & 1) == 1) res = res * t % p;
k >>= 1;
t = t * t % p;
}
return res ;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int a = scan.nextInt();
int b = scan.nextInt();
int n = scan.nextInt();
int p = b * 1000;
System.out.println(((a * qmi(10,n + 2,p)) % p) / b);
}
}
PREV51 观光铁路
资源限制
时间限制:2.0s 内存限制:256.0MB
问题描述
跳蚤国正在大力发展旅游业,每个城市都被打造成了旅游景点。
许多跳蚤想去其他城市旅游,但是由于跳得比较慢,它们的愿望难以实现。这时,小C听说有一种叫做火车的交通工具,在铁路上跑得很快,便抓住了商机,创立了一家铁路公司,向跳蚤国王请示在每两个城市之间都修建铁路。
然而,由于小C不会扳道岔,火车到一个城市以后只能保证不原路返回,而会随机等概率地驶向与这个城市有铁路连接的另外一个城市。
跳蚤国王向广大居民征求意见,结果跳蚤们不太满意,因为这样修建铁路以后有可能只游览了3个城市(含出发的城市)以后就回来了,它们希望能多游览几个城市。于是跳蚤国王要求小C提供一个方案,使得每只跳蚤坐上火车后能多游览几个城市才回来。
小C提供了一种方案给跳蚤国王。跳蚤国王想知道这个方案中每个城市的居民旅游的期望时间(设火车经过每段铁路的时间都为1),请你来帮跳蚤国王。
输入格式
输入的第一行包含两个正整数n、m,其中n表示城市的数量,m表示方案中的铁路条数。
接下来m行,每行包含两个正整数u、v,表示方案中城市u和城市v之间有一条铁路。
保证方案中无重边无自环,每两个城市之间都能经过铁路直接或间接到达,且火车由任意一条铁路到任意一个城市以后一定有路可走。
输出格式
输出n行,第i行包含一个实数tBi,表示方案B中城市i的居民旅游的期望时间。你应当输出足够多的小数位数,以保证输出的值和真实值之间的绝对或相对误差不超过1e-9。
样例输入
4 5
1 2
2 3
3 4
4 1
1 3
样例输出
3.333333333333
5.000000000000
3.333333333333
5.000000000000
样例输入
10 15
1 2
1 9
1 5
2 3
2 7
3 4
3 10
4 5
4 8
5 6
6 7
6 10
7 8
8 9
9 10
样例输出
10.000000000000
10.000000000000
10.000000000000
10.000000000000
10.000000000000
10.000000000000
10.000000000000
10.000000000000
10.000000000000
10.000000000000
数据规模和约定
对于10%的测试点,n <= 10;
对于20%的测试点,n <= 12;
对于50%的测试点,n <= 16;
对于70%的测试点,n <= 19;
对于100%的测试点,4 <= k <= n <= 21,1 <= u, v <= n。数据有梯度。
算法分析
不会