CF思维题3

A.Tit for Tat

题目链接

思路:首先不知道字典序的可以先baidu一下字典序
对于数字1、2、3…n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是 54321。
我们让最高位(也就是前面的元素)尽量小,但不能小于0(一旦小于0就跳出循环),同时还要使a[i]+1a[i]越靠后,影响就越小。

import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			int n = sc.nextInt();
			int k = sc.nextInt();
			int a[] = new int[n];
			for(int i=0;i<n;i++) {
				a[i] = sc.nextInt();
			}
			boolean flag = false;
			int l = 0;int r = n-1;
			while(l<r&&k>0) {
				for(int i=0;i<n;i+=0) {
					if(a[i]!=0&&k>0) {
						a[i]--;
						k--;
						a[n-1]++;
					}else {
						l++;
						i++;
						continue;
					}
				}
			}
			System.out.print(a[0]);
			for(int j=1;j<n;j++) {
				System.out.print(" "+a[j]);
			}System.out.println();
		}
	}
}

BA.rray and Peaks

题目链接

思路:这道题的大致就是将一条y=x的曲线经过有限次操作,得到一条有k个极大值点的曲线。下面举一个例子

1 2 3 4 5 → 1 2 3 5 4 → 1 3 2 5 4 在这里插入图片描述
通过这条直线的性质可以知道,从后往前与相邻的元素进行交换会得到一个极大值点,从前往后与相邻元素进行交换,会得到一个极小值点。注意,一个元素只能交换一次。
这里边有一种特殊情况,那就是n<k*2+1这种,这种是不满足条件的。

import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			int n = sc.nextInt();
			int k = sc.nextInt();
			int a[] = new int[n+1];
			for(int i=1;i<=n;i++) {
				a[i] = i;
			}
			if(n<k*2+1&&k!=0) {
				System.out.println(-1);
			}else {
				 for(int i=1;i<=2*k;i+=2) {
					 int x = a[n+1-i];
					 a[n+1-i]=a[n-i];
					 a[n-i]=x;
				 }
				 System.out.print(a[1]);
					for(int i=2;i<=n;i++) {
						System.out.print(" "+a[i]);
				}System.out.println();
			}
		}
	}
}

C.Candies and Two Sisters

原题链接

import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			int n = sc.nextInt();
			if(n%2!=0) {
				System.out.println(n/2);
			}else {
				System.out.println(n/2-1);
			}
		}
	}
}

D.Sum of Medians

题目链接

思路:分情况讨论
1.n=1时,将所有项加到一起就是答案
2.n!=1时,因为他是取的每一组中第n/2个数,所以对于每一小组来说如果n是奇数,可以忽略前n/2项,如果n是偶数,可以忽略前n/2-1项。然后对于原数列,就是相当于忽略了前k*y=n%2==0?n/2-1:n/2项,然后剩余项,每隔n/2项取一次即可

import java.util.Arrays;
import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			int n = sc.nextInt();
			int k = sc.nextInt();
			long a[] = new long[n*k];
			for(int i=0;i<n*k;i++) {
				a[i] = sc.nextLong();
			}
			Arrays.sort(a);
			int x = n/2;
			long s = 0;
			if(n==1) {
				for(int i=0;i<n*k;i++) {
					s+=a[i];
				}
			}
			else if(n==2) {
				for(int i=0;i<n*k;i+=2) {
					s+=a[i];
				}
			}else {
				x++;
				int y = n%2==0?n/2-1:n/2;
				for(int i=k*y;i<n*k;i+=x) {
					s+=a[i];
				}
			}
			System.out.println(s);
		}
	}
}

E.Rock and Lever

原题链接

思路:这道题主要是利用了位运算的性质以及排列组合的知识。
位运算性质:对于本题来说,用到了&运算以及^运算。&就是同时为1时才为1,其余为0.^01或者10是得到1,其余为0.
而对于本题来说只需要关注最高位即可,如果两个数的二进制的位数相同,那么最高位都是1,^之后就为0了,而&之后还是1,所以二进制位数相同的两个数a&b>=a^b如果位数不同,那么其中必定有一个数是位数不够用0补的,也就是会出现一个0,一个1的情况,这种情况下a&b<a^b
接下来就是排列组合的知识了,两两结对,会发现所有情况就是前n-1项和(n为二进制中相同位数的个数)

import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			long s[] = new long[33];
			int n = sc.nextInt();
			int a[] = new int[n];
			for(int i=0;i<n;i++) {
				a[i] = sc.nextInt();
				String str = Integer.toBinaryString(a[i]);
				s[str.length()]++;
			}
			long ans = 0;
			for(int i=1;i<=32;i++) {
				if(s[i]>1)ans+=((s[i]-1)*(s[i]-1)+s[i]-1)/2;
			}
			System.out.println(ans);
		}
	}
}

F.Berland Poker

原题链接

思路:第一个人要给他尽量多的王,其余人平均分王,如果还有剩余的(也就是剩余的王%人数!=0),就再给一部分人平均分一下。

import java.util.Arrays;
import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			int n = sc.nextInt();
			int m = sc.nextInt();
			int k = sc.nextInt();
			int a[] = new int[k];
			if(m>n/k) {
				a[0]=n/k;
				m-=n/k;
			}else {
				System.out.println(m);
				continue;
			}
			while(m>0) {
				for(int i=1;i<k&&m>0;i++) {
					a[i]++;
					m--;
				}
			}
			Arrays.sort(a);
			System.out.println(a[k-1]-a[k-2]);
		}
	}
}

G.Buying Shovels

原题链接

思路:这道题的本质就是求n在1-k范围内的最大因子。
由于数值比较大,所以用遍历到 n \sqrt{n} n ,如果n%i==0,那么将n/i以及i都存在ArrayList里,接下来遍历ArrayList找出小于k的最大的元素即可。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
//求小于k的最大约数
public class G_BuyingShovels {
	public static int n;
	public static int k;
	public static ArrayList<Integer>al = new ArrayList<>();
	public static void check(int x) {
		al.clear();//得先清一下
		int max = 1;
		for(int i=1;i*i<=x;i++) {
			if(x%i==0) {
				al.add(i);
				al.add(x/i);
			}
		}
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			n = sc.nextInt();
			k = sc.nextInt();
			int max = 1;
			if(k>=n) {
				System.out.println(1);
			}else {
				check(n);
				Collections.sort(al);
				for(int i=0;i<al.size();i++) {
					if(al.get(i)<=k) {
						max = Math.max(max,al.get(i));
					}
				}
				System.out.println(n/max);
			}
		}
	}
}

I.Alice, Bob and Candies

原题链接

这道题我感觉洛谷的题目翻译不是很清晰,可以自己百度翻译,看懂题意之后模拟即可。

import java.util.Arrays;
import java.util.Scanner;
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while(t-->0) {
			int n = sc.nextInt();
			int s[] = new int[n];
			for(int i=0;i<n;i++) {
				s[i] = sc.nextInt();
			}
			int a = 0;//A总得分
			int b = 0;//B总得分
			int index = 0;//记录回合数
			int nowa = 0;//记录当前a的增量
			int nowb = 0;//记录当前b的增量
			int l = 0;
			int r = n-1;
			while(l<=r) {
				while(l<=r&&nowa<=nowb) {
					a+=s[l];
					nowa+=s[l];
					l++;
				}
				if(l<=r)index++;
				nowb=0;
				while(l<=r&&nowb<=nowa) {
					b+=s[r];
					nowb+=s[r];
					r--;
				}
				if(l<=r)index++;
				nowa=0;
			}
			System.out.println(index+1+" "+a+" "+b);
		}
	}
}

J.Anti-Sudoku

原题链接

这道题是一个思维题,对于一个数独来说,对于一行一列来说,如果想使这一行一列刚好有两个相同的元素,那么只需要将这一行一列交点处的值换成与当前值不同的即可(1到9)。并且还要考虑每一个小的九宫格,所以就要求每一个小的九宫格里有一个要被替换,而且被替换的元素必须是不同行不同列的。
扩展到九行九列,就是下图。
在这里插入图片描述
替换黑色的部分即可。(答案不唯一)

import java.util.Scanner;
//要用StringBuilder
public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		sc.nextLine();
		while(t-->0) {
			char a[][] = new char[9][9];
			for(int i=0;i<9;i++) {
				String str = sc.nextLine();
				a[i] = str.toCharArray();
			}
			a[0][0]=a[0][0]=='1'?'2':'1';
			a[1][3]=a[1][3]=='1'?'2':'1';
			a[2][6]=a[2][6]=='1'?'2':'1';
			a[3][1]=a[3][1]=='1'?'2':'1';
			a[4][4]=a[4][4]=='1'?'2':'1';
			a[5][7]=a[5][7]=='1'?'2':'1';
			a[6][2]=a[6][2]=='1'?'2':'1';
			a[7][5]=a[7][5]=='1'?'2':'1';
			a[8][8]=a[8][8]=='1'?'2':'1';
			StringBuilder sb = new StringBuilder();
			for(int i=0;i<9;i++) {
				for(int j=0;j<9;j++) {
					sb.append(a[i][j]);
				}
				if(i!=8)sb.append("\n");
			}
			System.out.println(sb);
		}
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值