题目描述
在观星的时候,一种常用的方式是划出类似于正方形的区域内,确定其中所有星星的坐标。
现在我们在星空(一个无限大的二维平面)上简历坐标系。由于星星很小,我们忽略它的面积,认为每一个星星是一个点,且所有星星的坐标都是整数。
幸运星的定义是这一颗星星在这个平面内,正上,正下,正左,正右都有其他的星星(不一定相邻)。
现在,我们已经将这个正方形的取余取出,并且将她们所在的坐标给你。现在希望你能计算,这个平面内有多少颗幸运星?
输入
输入第一行包含一个数n,代表正方形区域内星星的总数。
接下来n行,每行两个整数 x i x_{i} xi, y i y_{i} yi,代表这颗星星的坐标。
( n ⩽ 2000 , − 1000 ⩽ x i , y i ⩽ 1000 n \leqslant 2000, -1000 \leqslant x_{i},y_{i}\leqslant 1000 n⩽2000,−1000⩽xi,yi⩽1000,没有两颗星星的坐标是相同的。)
输出
输出包含一个数,即有多少颗星星是幸运星。
样例输入
8
0 0
0 1
0 2
0 3
1 1
1 2
-1 1
-1 2
样例输出
2
提示
样例解释:
有两颗幸运星,分别是(0,1),(0,2)
题解:暴力枚举ac,可怕吧?
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] sky = new int[n][2];
for (int i = 0; i < n; i++) {
sky[i][0] = sc.nextInt(); // 横坐标
sky[i][1] = sc.nextInt(); // 纵坐标
}
int res = 0;
for (int i = 0; i < n; i++) {
int x = sky[i][0];
int y = sky[i][1];
boolean up = false;
boolean down = false;
boolean left = false;
boolean right = false;
for (int j = 0; j < n; j++) {
if(i == j) continue;
if(sky[j][0] == x){ // 横坐标相等
if(sky[j][1] < y){ // j在i的下边
down = true;
}else{ // j在i的上边
up = true;
}
}
if(sky[j][1] == y){ // 纵坐标相等
if(sky[j][0] < x){ // 右边
right = true;
}else{ // 左边
left = true;
}
}
}
if(up && down && left && right){
res++;
}
}
System.out.println(res);
}
}
题目描述
货币数值的规范化是金融公司的一个问题,现在你需要写一个程序来解决这一问题:
- 货币数值的整数部分要求每3位加一个英文‘,’(不含引号)。例如12345678应该规范为12,345,678
- 货币数值最多只有两位小数,如果有多余的小数位数应当舍去。注意,不是四舍五入。
- 负数代表欠款,在规范化后应当在数值两端加上括号’(’ 和 ‘)’ ,然后省略掉负号。
- 应当在数值前面,前括号后面(如果有括号的话)加上金钱符号’$’(不含引号)
现在给你一个数字,请你规范化这一数字
输入
输入包含多种数据,每组数据一行一个数字,可能为小数,整数,负整数,负小数或者零。
数据保证数字没有前导0,保证不会出现欠0元的情况。
输出
输出规范化后的内容
样例输入
203323
0.0
0.00000
0.009212121
343444323.32432
-12344.1
-12345678.9
样例输出
$203,323.00
$0.00
$0.00
$0.00
$343,444,323,32
($12,344.10)
($12,345,678.90)
提示
范围
每个字符串长度不会超过100
题解
常规思路,注意语法。
import java.util.Scanner;
public class ex2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String str = sc.next();
StringBuilder sb = new StringBuilder(str);
int pointIndex = sb.indexOf(".");
if (pointIndex == -1) sb.append(".00");
else {
// 将小数点后保留两位
int i = pointIndex;
if (i + 2 < sb.length() - 1) { // .后面位数大于2,比较索引
sb.replace(i + 3, sb.length(), "");
} else { // 相等或不足2位
while (i + 2 > sb.length() - 1) {
sb.append("0");
}
}
// 将小数点前用","隔开
i = i - 3; // 如果要加",",应加在i处
while (i - 1 >= 0 && Character.isDigit(sb.charAt(i - 1))) { // 如果i前面不是空,也不是符号,则加","
sb.insert(i, ",");
i -= 3;
}
// 如果是负数,加()和$
if (sb.charAt(0) == '-') {
sb.replace(0, 1, "$");
sb.insert(0, "(");
sb.append(")");
} else { // 如果不是负数
sb.insert(0, "$");
}
System.out.println(sb.toString());
}
}
}
}
题目描述
现在有n名选手进行轮流报数,选手按顺序编号为1~n,另外我们会给出一个序列A,游戏会进行n轮,每轮会出局一名选手,第i轮淘汰的选手最后的排名是n-i+1,即第一轮出局的是倒数第一。出局的选手不会参与下一轮报数。
每轮游戏都是从第一个选手开始报数,即如果1号选手仍在,则从1号选手开始,否则从2号选手开始,以此类推,但是注意,每轮报数是从0开始的,第i轮时,第一个报到A[i]的选手会出局,且当前轮游戏结束。A[i]有可能大于当前的剩余人数,则最后一个人报完以后,会由第一个人接着报,知道报出A[i]。
输入
输入第一行包含一个正整数n,表示有n名选手。(1<= n<=100000)
输入第二行包含n个正整数,表示序列A。(0 <= A[i]<= 10^9)
输出
输出包含n行,每行一个正整数,第i行的正整数表示i号选手的排名是多少。即输出是一个1~n的排列。
样例输入
4
1 2 1 2
样例输出
1
4
2
3
提示
样例解释
第一轮中,1-4号选手报数分别是0,1,+,+(+代表未报数),因为A[1]=1,所以2号选手出局,排名为4。
第二轮中,1-4号选手报数为0,-,1,2(-代表出局),因为A[2]=2,所以4号选手出局,排名为3。
第三轮中,1-4号选手报数为0,-,1,-,因为A[3]=1,所以3号选手出局,排名为2.
第四轮中只有1号选手了,所以他会报所有的数字,最后出局。
题解思路
按题目的要求做,用一个数组记录是否出局,另一个数组记录出局人的排名
注意为了防止越界,index要模n。另外一个细节是:每次从第一个人开始报数!
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] signal = new int[n]; // 未出局记为0,出局记为1
int[] res = new int[n]; // 记录对应位置是第几个出局的人
int index = 0;
for (int i = 0; i < n; i++) { // 找出第i个人出局的人。
int count = sc.nextInt();
index = 0; // 每一轮是从第一个选手开始报数
for (int j = 0; j < count; j++) {
index = (index + 1) % n;
while (signal[index] == 1) {
// 如果当前index位置已出局,index后移一位
index = (index + 1) % n;
}
// index是当前数j的位置
}
signal[index] = 1; // 将出局人的位置index记为1
res[index] = n - i; // index处记录排名
}
// 按位置输出排名
for (int i = 0; i < n; i++) {
System.out.println(res[i]);
}
}
}
题目描述
熊爷爷的超市正在打折活动当中!
目前,你和你的家里人一共k个人一起去买生活用品。由于打折活动力度很大,每个人只能去付款一次,但是这一次买的东西价格是不做限制的。
熊爷爷的超市物品分为两类:A类和B类物品,活动是如果一个人买的商品中含有A类物品,那么他买的所有物品中最便宜的一件物品半价。如果一个人买的商品中只有B类物品,那么他买的物品不打折。
你们计划要买n个物品,现在将这n个物品的信息给你,请你计算如何分配k位家人比较和算。
输入
第一行有两个整数n,k,代表物品的数量和人的数量。
接下来n行,每行两个整数u,v描述一个物品。u代表物品的价格,v代表商品的种类。如果v为1,代表其为A类商品。如果v为2,代表其为B类商品。
1<= n, k <= 1000, 1<= u<= 1000000, v ∈ \in ∈ {1, 2}
输出
输出一行一个小数,表示所需要的最少的钱数。保留两位小数输出。
样例输入
5 2
10 1
2 2
5 2
8 1
9 1
样例输出
28.00
提示
样例解释:
第一个人只买第一个物品,第二个人买剩下的物品。
第一个人由于买了A类物品,最便宜的物品半价,付款5元。
第二个人由于也买了A类物品,最便宜的物品半价,付款23元(物品二半价)。
(买法不唯一)
题解 题目描述 两个数是相似的,当且仅当他们位与起来不为0。例如3和5是相似的,因为3的二进制为011,5的二进制为101,他们位与起来为001不为0。 输入 输入第一行包括一个整数n,代表序列a的长度 输出 输出n个数 样例输入 4 样例输出 -1 -1 1 1 提示 样例解释 题解
使用贪心法则
如果现在只有一个人,没有选择,只能查看是否有A,有A的情况下,省钱为minPrice/2.
如果有2个人,那么第一个人要怎么分,才能使省的钱最多呢?
首先第二个人最多可以省maxA/2,所以肯定要分出最大的A给第二个人,并且保证第二个人省maxA/2,那么自己还有没有A呢?如果有,也省钱minPrice/2。如果没有,则不省钱了,但总体来说,省的钱从minPrice/2变成了maxA/2,省的钱变多了。而且可以验证是这个策略分钱是最多的。那么怎么保证第二个人省priceA/2呢?保证A是里面价格最小的即可:分给第二个人的B都大于等于A,或者只给第二个人分A不分B,B留在第一个人手里,不会有任何影响,因为我们只用考虑该单中的最小值。
扩展到k个人的情况,为了减少计算量,我们采取以下策略:
每一次都将剩下的商品里最大的A单独分给一个人买单,保证省钱是maxA/2。
重复这个操作,如果过程中A没了,就再也不享受折扣了。
最后一单包含了所有B商品和剩余A,也可能没有A了。
如果到最后一单还有A,要特别考虑,因为没办法保证A是最后一单里价格最小的,所以这一单省的钱是min{A,B}。
所需最小的钱数 = 总价 - 省钱最多。
结束。
分析复杂度
需要给A降序排列,并且找到最小的B。如果k<
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
public class Main {
private static int MIN = (int) 1e6 + 10;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // n个物品
int k = sc.nextInt(); // k个人
int min = MIN;
int sum = 0; // 记录总价
ArrayList<Integer> Aprice = new ArrayList<>();
ArrayList<Integer> Bprice = new ArrayList<>();
for (int i = 0; i < n; i++) {
int price = sc.nextInt();
int kind = sc.nextInt();
if (kind == 1) { // 物品i是A类
Aprice.add(price);
sum += price;
} else { // 物品i是B类
min = Math.min(min, price); // 找出B类中价格最小的
Bprice.add(price);
sum += price;
}
}
// A需要排序,B只需要找出最小值。
Collections.sort(Aprice); // A从小到大排序
int count = Aprice.size() - 1;
double res = 0; // 记录可以省下的钱总数
while (k > 0 && count >= 0) { // 还有人,并且还有A物品
if (k == 1) { // 只剩下1个人,需买下剩下的A物品与所有B物品
res += (double) Math.min(Aprice.get(0), min) / 2;
break;
} else {
res += (double) Aprice.get(count) / 2;
count--;
k--;
}
}
System.out.printf("%.2f",sum-res);
}
}
T5 相似
现在,给序列a1, a2, … , an我们希望你找出,对于任意i ∈ \in ∈[1,n],是否存在j ∈ \in ∈[1,n],使得ai,aj不相似。
接下来一行n个整数,空格隔开,代表序列a
1<=n<=100000, 1<=ai<=106
如果对于i个数,存在j ∈ \in ∈(1, n],使得ai, aj不相似,输出1,否则输出-1
3 5 6 1
唯一一对不相似的数是6和1,故6和1的答案为1,其余为-1。
我没有做到这一题,看dalao们做的,好多都是暴力枚举然后通过45%case。
我觉得原因可能是,n非常大,但ai并不是很大,所以在遍历少数n的时候,就可以找到不相似的了【只是一种可能性】,如果找到了就即时退出吧,别再找下去了。
我感觉我做的也是暴力枚举,所以非常不安,感觉写了个错误答案。如果有dalao知道ac方法,请告诉我吧。
大致思路就是,如果a&b==0
–>a与b不相似,例如1&6==0
,1是001,6是110;2&6==1
,2是010,6是110。import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
int[] res = new int[n]; // 记录结果,初始化都是-1(假设找不到不相似)
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
res[i] = -1;
}
for (int i = 0; i < n; i++) {
if(res[i] != 1){ // 已经有不相似的了,不用再找
for (int j = 0; j < n; j++) {
if(i != j && (arr[i]&arr[j]) == 0){ // i,j不相似
res[i] = 1;
res[j] = 1;
break;
}
}
}
}
// 遍历res输出结果
for (int i = 0; i < res.length-1; i++) {
System.out.print(res[i]+" ");
}
System.out.print(res[res.length-1]);
System.out.println();
}
}