WY10 分苹果
题目描述
n 只奶牛坐在一排,每个奶牛拥有 ai 个苹果,现在你要在它们之间转移苹果,使得最后所有奶牛拥有的苹果数都相同,每一次,你只能从一只奶牛身上拿走恰好两个苹果到另一个奶牛上,问最少需要移动多少次可以平分苹果,如果方案不存在输出 -1。
输入描述:
每个输入包含一个测试用例。每个测试用例的第一行包含一个整数 n(1 <= n <= 100),接下来的一行包含 n 个整数 ai(1 <= ai <= 100)。
输出描述:
输出一行表示最少需要移动多少次可以平分苹果,如果方案不存在则输出 -1。
示例1
输入
4
7 15 9 5
输出
3
解题思路:
方案存在条件:
1.苹果数必须全奇或全偶(因为你每次拿两个苹果不会改变苹果数的奇偶性质,但是最后要保证都变成为平均值,所以奇偶性必须相同)
2.总苹果数必须能整除奶牛只数,即平均数必须为整数
所以其他情况都返回-1
当满足前面两个条件后,我们只需要遍历数组,计算每个苹果数和平均值的差值,然后相加起来得到的答案res,再除以4即为移动次数(这里为啥除以4,是因为我们的res中是有取出和放入的,所以操作的苹果数只有 res/2 个,然后我们每次操作是2个苹果,所以移动次数为 res/4 )
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNextInt()){
int n = sc.nextInt();
int[] nums = new int[n];
int sum = 0;
int odd = 0;
for(int i = 0;i<nums.length;i++){
nums[i] = sc.nextInt();
if(nums[i]%2!=0){
if(odd==-1){
System.out.println(-1);
return;
}
odd = 1;
}else{
if(odd==1){
System.out.println(-1);
return;
}
odd = -1;
}
sum+=nums[i];
}
if(sum%n!=0){
System.out.println(-1);
return;
}
int avg = sum/n;
int count = 0;
for(int i = 0;i<nums.length;i++){
if(nums[i]!=avg){
count+=Math.abs(nums[i]-avg);
}
}
System.out.println(count/4);
}
}
}
WY11 星际穿越
描述
航天飞行器是一种复杂而又精密的仪器,飞行器的损耗主要集中在发射和降落的过程,科学家根据实验数据估计,如果在发射过程中,产生了 x 程度的损耗,那么在降落的过程中就会产生 x2 程度的损耗,如果飞船的总损耗超过了它的耐久度,飞行器就会爆炸坠毁。问一艘耐久度为 h 的飞行器,假设在飞行过程中不产生损耗,那么为了保证其可以安全的到达目的地,只考虑整数解,至多发射过程中可以承受多少程度的损耗?
数据范围:1 \le h \le 10^{18} \1≤h≤10
18
输入描述:
每个输入包含一个测试用例。每个测试用例包含一行一个整数 h (1 <= h <= 10^18)。
输出描述:
输出一行一个整数表示结果。
示例1
输入:
10
输出:
2
示例2
输入:
1
输出:
0
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
Long h=Long.parseLong(br.readLine());
long left=0,right=(long)Math.sqrt(h)+1,x=0;
while(left<right){
long mid=left+((right-left)>>1);
if(mid*(mid+1)>h){
right=mid-1;
}
else{
x=mid;
left=mid+1;
}
}
System.out.println(x);
}
}
WY12 藏宝图
描述
牛牛拿到了一个藏宝图,顺着藏宝图的指示,牛牛发现了一个藏宝盒,藏宝盒上有一个机关,机关每次会显示两个字符串 s 和 t,根据古老的传说,牛牛需要每次都回答 t 是否是 s 的子序列。注意,子序列不要求在原字符串中是连续的,例如串 abc,它的子序列就有 {空串, a, b, c, ab, ac, bc, abc} 8 种。
输入描述:
每个输入包含一个测试用例。每个测试用例包含两行长度不超过 10 的不包含空格的可见 ASCII 字符串。
输出描述:
输出一行 “Yes” 或者 “No” 表示结果。
示例1
输入:
nowcodecom
ooo
输出:
Yes
直接双指针跑起来就行。两个指针p1和p2初始分别指向两个字符串s和t的起始字符,如果相等,两个指针都移动,否则只移动p1。最后检查一下p2是不是移动到了t.length就行,如果到了就说明所有t中的字符都在s中按照t字符串的字符顺序出现过了。
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
char [] s=br.readLine().toCharArray();
char [] t=br.readLine().toCharArray();
int p1=0,p2=0;
while(p1<s.length && p2<t.length){
if(s[p1]==t[p2]){
p1++;
p2++;
}
else{
p1++;
}
}
System.out.println(p2==t.length?"Yes":"No");
}
}
WY13 数列还原
描述
牛牛的作业薄上有一个长度为 n 的排列 A,这个排列包含了从1到n的n个数,但是因为一些原因,其中有一些位置(不超过 10 个)看不清了,但是牛牛记得这个数列顺序对的数量是 k,顺序对是指满足 i < j 且 A[i] < A[j] 的对数,请帮助牛牛计算出,符合这个要求的合法排列的数目。
输入描述:
每个输入包含一个测试用例。每个测试用例的第一行包含两个整数 n 和 k(1 <= n <= 100, 0 <= k <= 1000000000),接下来的 1 行,包含 n 个数字表示排列 A,其中等于0的项表示看不清的位置(不超过 10 个)。
输出描述:
输出一行表示合法的排列数目。
示例1
输入:
5 5
4 0 0 2 0
输出:
2
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int n = in.nextInt();
int k = in.nextInt();
int[] array = new int[n];
boolean[] flag = new boolean[n];
for (int i = 0; i < n; i++) {
array[i] = in.nextInt();
if (array[i] != 0) flag[array[i]-1] = true;
}
//找出缺失数字
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++)
if (!flag[i]) list.add(i+1);
//得到缺失数字全排列
ArrayList<ArrayList<Integer>> listAll = new ArrayList<>();
getPermutation(listAll, list, 0);
//原始数组的顺序对
int orderPairCount = getOrderPairByArray(array);
int res = 0;
//依次求出产生的全排列和原始数组一起的顺序对
for (ArrayList<Integer> arrayList: listAll) {
int count = orderPairCount;
int[] temp = Arrays.copyOf(array, array.length);
count += getOrderPairByNew(temp, arrayList);
if (count == k) res++;
}
System.out.println(res);
}
}
private static int getOrderPairByNew(int[] array, ArrayList<Integer> list) {
int count = 0;
int j = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == 0) {
array[i] = list.get(j++);
for (int k = 0; k < i; k++)
if (array[k] < array[i]) count++;
for (int k = i+1; k < array.length; k++)
if (array[i] < array[k]) count++;
}
}
return count;
}
private static int getOrderPairByArray(int[] array) {
int count = 0;
for (int i = 0; i <array.length; i++) {
for (int j = i + 1; j < array.length && array[i] != 0; j++)
if (array[j] != 0 && array[i] < array[j])
count++;
}
return count;
}
private static void getPermutation(ArrayList<ArrayList<Integer>> listAll,
ArrayList<Integer> list, int start) {
if (start == list.size() - 1)
listAll.add(new ArrayList<>(list));
else {
for (int i = start; i < list.size(); i++) {
Collections.swap(list, start, i);
getPermutation(listAll, list, start + 1);
Collections.swap(list, start, i);
}
}
}
}
WY14 混合颜料
描述
你就是一个画家!你现在想绘制一幅画,但是你现在没有足够颜色的颜料。为了让问题简单,我们用正整数表示不同颜色的颜料。你知道这幅画需要的n种颜色的颜料,你现在可以去商店购买一些颜料,但是商店不能保证能供应所有颜色的颜料,所以你需要自己混合一些颜料。混合两种不一样的颜色A和颜色B颜料可以产生(A XOR B)这种颜色的颜料(新产生的颜料也可以用作继续混合产生新的颜色,XOR表示异或操作)。本着勤俭节约的精神,你想购买更少的颜料就满足要求,所以兼职程序员的你需要编程来计算出最少需要购买几种颜色的颜料?
输入描述:
第一行为绘制这幅画需要的颜色种数n (1 ≤ n ≤ 50) 第二行为n个数xi(1 ≤ xi ≤ 1,000,000,000),表示需要的各种颜料.
输出描述:
输出最少需要在商店购买的颜料颜色种数,注意可能购买的颜色不一定会使用在画中,只是为了产生新的颜色。
示例1
输入:
3
1 7 3
输出:
3
import java.util.*;
import java.io.*;
public class Main {
/**
*矩阵论中的知识表明,最大线性无关组是解的最基本的形式。
*这个题目类似于求矩阵的最大线性无关组,用高斯消元法就可以了,正向算一遍即可,反向不用计算(我们只关心无关组的向量个数,不关心具体解的形式)。
*多元方程,我们从左到右不为零开始消元,对于二进制数,那就是从大的数开始就可以了。
*用一个函数判断每一位是否为零,为零才消元。遍历的时候注意方程有几个,我们每次遍历的目标是消灭一列的1,使每一列最多1个一,
*但是方程不够的时候,就不必向下消了,已经可以结束了。
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
int[] arrColor = new int[n];
String[] arrInput = br.readLine().trim().split(" ");
for (int i=0; i<n; i++) {
arrColor[i] = Integer.parseInt(arrInput[i]);
}
Arrays.sort(arrColor);//排序
int computLoopCnt = 0;//记录循环的个数
for (int i=31; i>=0; i--) {//遍历每一位,最大的数的该位为零就跳过
int row = (n - 1) - computLoopCnt;
if (row <= 0) {//如果行数不够了,直接停止
break;
}
if (isNbitIsOne(arrColor[row],i)) {//判断该为是否为零
computLoopCnt++;
for (int j=row-1; j>=0; j--) {
if (isNbitIsOne(arrColor[j],i)) {
arrColor[j] = arrColor[row] ^ arrColor[j];
}
}
Arrays.sort(arrColor, 0, row );//每次计算后排序,因为异或后可能变大,要正确找到最大的
}
}
int baseNum = 0;
for (int i=0; i<n; i++) {
if (arrColor[i] != 0) {
baseNum++;
}
}
System.out.println(baseNum);
}
public static boolean isNbitIsOne(int a, int n) {//判断第n位(顺寻方向:自右向左)是否为零
if (n > 32) {
throw new IllegalArgumentException();
}
int test = 1 << n;
boolean isOne = false;
if (test == (a & test)) {
isOne = true;
}
return isOne;
}
}
WY15 幸运的袋子
描述
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
输入描述:
第一行输入一个正整数n(n ≤ 1000) 第二行为n个数正整数xi(xi ≤ 1000)
输出描述:
输出可以产生的幸运的袋子数
示例1
输入:
3
1 1 1
输出:
2
深度优先搜索加强剪枝
首先计算每个球的数字出现的次数,从小(2开始)到大添加,添加的个数为(0…n)n为这个数字出现的最大次数
剪枝:乘积大于和 + 1 出现的次数
import java.util.Scanner;
/**
* Created by ZLei on 2018/8/7.
*/
public class Main {
public static final int NUMBER_ON_BALL = 1001;
public static int ans = 0;
public static int ballMax = 0;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
ans = 0;
ballMax = 0;
int ballNum = scanner.nextInt();
int[] balls = new int[NUMBER_ON_BALL];
for(int i = 0; i < ballNum; i++){
int numOnBall = scanner.nextInt();
balls[numOnBall]++;
ballMax = Math.max(numOnBall, ballMax);
}
dfs(2,balls,1,0);
System.out.println(ans);
}
scanner.close();
}
public static void dfs(int index, int balls[], int mul, int add){
if(mul > add + balls[1]) return;
if(index == (ballMax+1)){
ans += balls[1] - (mul - add);
return;
}
for(int j = 0; j <= balls[index]; j++){
int newMul = mulNum(mul, index,j);
int newAdd = addNum(add,index,j);
if(newMul > newAdd + balls[1]) break;
dfs(index+1, balls,newMul,newAdd );
}
}
public static int addNum(int oldAdd, int addNum, int addTime){
return oldAdd + addNum * addTime;
}
public static int mulNum(int oldMul, int mulNum, int mulTime){
for(int i = 0; i < mulTime; i++){
oldMul *= mulNum;
}
return oldMul;
}
}
WY16 不要二
描述
二货小易有一个W*H的网格盒子,网格的行编号为0H-1,网格的列编号为0W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。
对于两个格子坐标(x1,y1),(x2,y2)的欧几里得距离为:
( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) 的算术平方根
小易想知道最多可以放多少块蛋糕在网格盒子里。
输入描述:
每组数组包含网格长宽W,H,用空格分割.(1 ≤ W、H ≤ 1000)
输出描述:
输出一个最多可以放的蛋糕数
示例1
输入:
3 2
输出:
4
import java.util.Scanner ;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in) ;
int a = in.nextInt() ;
int b = in.nextInt() ;
int count = 0;
for(int i = 0; i< a; i++)
for(int j = 0; j< b; j++){
int m = i%4;
int n = j%4;
if(m==n || (m==1&& n==0) ||(m==0&& n==1)
|| (m==3&& n==2) ||(m==2&& n==3))
count++ ;
}
System.out.println(count) ;
}
}
WY17 解救小易
描述
有一片1000*1000的草地,小易初始站在(1,1)(最左上角的位置)。小易在每一秒会横向或者纵向移动到相邻的草地上吃草(小易不会走出边界)。大反派超超想去捕捉可爱的小易,他手里有n个陷阱。第i个陷阱被安置在横坐标为xi ,纵坐标为yi 的位置上,小易一旦走入一个陷阱,将会被超超捕捉。你为了去解救小易,需要知道小易最少多少秒可能会走入一个陷阱,从而提前解救小易。
输入描述:
第一行为一个整数n(n ≤ 1000),表示超超一共拥有n个陷阱。 第二行有n个整数xi,表示第i个陷阱的横坐标 第三行有n个整数yi,表示第i个陷阱的纵坐标 保证坐标都在草地范围内。
输出描述:
输出一个整数,表示小易最少可能多少秒就落入超超的陷阱
示例1
输入:
3
4 6 8
1 2 1
输出:
3
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[] x = new int[n];
for(int i = 0; i < n; i++){
x[i] = sc.nextInt() - 1;
}
int min = Integer.MAX_VALUE;
for(int i = 0; i < n; i++){
int y = sc.nextInt();
min = Math.min(min, y - 1 + x[i]);
}
System.out.println(min);
}
sc.close();
}
}