A - Sort the Subarray
大意:在s1找一个最大的 [l,r] 子区间,使其经过从小到大的排序后 能够变成 s2
题解:先确定最小的区间,然后慢慢扩大。
最小区间的确定:s1和s2第一个不相等的数开始,到最后一个不相等的数结尾
向两边扩大区间:如果本来就是从小到大排序的,那么就算sort也无影响,否则停止扩展
import java.util.Scanner;
/*
*@filename: Demo1
*@author: lyh
*@date:2023/4/24 19:09
*@version 1.0
*@description TODO
*/
public class Demo1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0){
int n=scanner.nextInt();
int[] vis1=new int[n+1];
int[] vis2=new int[n+1];
for(int i=1;i<=n;i++){
vis1[i]=scanner.nextInt();
}
boolean flag=true;
int left=0,right=0;
for(int i=1;i<=n;i++){
vis2[i]=scanner.nextInt();
if(flag&&vis2[i]!=vis1[i]){
left=i;
flag=false;
}else if(vis2[i]!=vis1[i]){
right=i;
}
}
while(left-1>0){
if(vis2[left]>=vis2[left-1]){
left--;
}
else break;
}
while(right+1<=n){
if(vis2[right]<=vis2[right+1]){
right++;
}
else break;
}
System.out.println(left+" "+right);
}
}
}
B - Tear It Apart
大意:给定一个字符串,操作多次后只剩下同一字符,每次操作消除不相邻的多个字符,求最小操作次数
题解:剩下的那个同一字符将字符串分成了多个区间端,就像隔离带一样。并且我们只要处理最长子串就可以了(因为其他的肯定能顺带移除完毕)。
如何寻找该同一字符:遍历字符串每种已有的字母,计算他们分割子串里的最长子串长度,取最小
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*
*@filename: Demo2
*@author: lyh
*@date:2023/4/25 14:46
*@version 1.0
*@description TODO
*/
public class Demo2 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0) {
String s=scanner.next();
int length=s.length();
Map<Character,Integer>map=new HashMap<>(30);
for(int i=0;i<length;i++){
if(!map.containsKey(s.charAt(i)))map.put(s.charAt(i),1);
}
int minn=Integer.MAX_VALUE;
for (Map.Entry<Character,Integer>entry:map.entrySet()) {
int count=0,temp=0;
for(int i=0;i<length;i++){
if(s.charAt(i)!=entry.getKey()){
count++;
}else{
temp=Math.max(temp,count);
count=0;
}
}
temp=Math.max(temp,count);//最后也要比较一次!
minn=Math.min(temp,minn);
}
int ans=0;
while(minn>0){
minn=minn>>1;//因为不相邻就可以一起消除
ans++;
}
System.out.println(ans);
}
}
}
C - Yura's New Name
大意:给出一个仅由 ^ 和 _ 组成的字符串 ,你可以在任意位置添加^或 _ 字符,使得字符串满足:
- 任意字符要么属于某一子串 ^_^ 的一部分,要么属于某一子串 ^^ 的一部分。
求最少添加的字符数量。
题解:感觉和 括号匹配 是一个题型。开头要求一定得是'^',两个连续的'_'中间需要加'^',以'_'结尾需要加'^'。特殊情况只有一个'^'需要注意判断。
import java.util.ArrayList;
import java.util.Scanner;
/*
*@filename: Demo2
*@author: lyh
*@date:2023/4/25 14:46
*@version 1.0
*@description TODO
*/
public class Demo2 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0) {
int ans=0;
String s=scanner.next();
int length=s.length();
if(length==1&&s.charAt(0)=='^'){
ans++;
System.out.println(ans);
continue;
}
if(s.charAt(0)!='^')ans++;
for(int i=0;i<length-1;i++){
if(s.charAt(i)==s.charAt(i+1)&&s.charAt(i)=='_'){
ans++;
}
}
if(s.charAt(length-1)=='_')ans++;
System.out.println(ans);
}
}
}
F - Li Hua and Maze
大意:求最少设置多少个障碍物,可以使起点永远无法到达终点。只能上下左右走。
题解:很简单,封住起点或终点,取封这两个需要的最小障碍物数
import java.util.Scanner;
/*
*@filename: Demo1
*@author: lyh
*@date:2023/4/24 19:09
*@version 1.0
*@description TODO
*/
public class Demo1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0) {
int n = scanner.nextInt();
int m = scanner.nextInt();
int x1= scanner.nextInt();
int y1= scanner.nextInt();
int x2= scanner.nextInt();
int y2= scanner.nextInt();
int getOutStep1=getStep(x1,y1,n,m);
int getInStep2=getStep(x2,y2,n,m);
System.out.println(Math.min(getOutStep1, getInStep2));
}
}
public static int getStep(int x1,int y1,int n,int m){
int ans=0;
if(x1-1>=1){
ans++;
}
if(x1+1<=n){
ans++;
}
if(y1+1<=m){
ans++;
}
if(y1-1>=1){
ans++;
}
return ans;
}
}
G - Li Hua and Pattern
大意:李华有一个大小为 n×n 的图案,每个格子为蓝色或红色。他可以进行恰好 k 次操作。每一次操作,他选择一个格子并改变其颜色(红变蓝,蓝变红)。每个格子可以被选择任意多次。是否可能使得操作后的图案中心对称(翻转180度看起来一样)?
题解:首先,遍历每个点,看它与其中心对称的点相比颜色是否一样,如果不一样则需要翻转一次,因为是中心对称,我们只需要遍历前面一半的点就可以了。特别注意的是如果n为奇数需要特别多遍历一行。
如果修改次数大于k,那肯定不行。如果小于k,分n的奇偶性判断:
- 若n为奇数,一定可以,因为正中心的小正方形无论翻转多少次都不影响整体,可以消耗多余的操作次数
- 若n为偶数,剩下多余的次数也要为偶数才行
import java.util.Scanner;
/*
*@filename: Demo1
*@author: lyh
*@date:2023/4/24 19:09
*@version 1.0
*@description TODO
*/
public class Demo1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0) {
int n=scanner.nextInt();
int k=scanner.nextInt();
int[][] vis=new int[n+1][n+1];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
vis[i][j]=scanner.nextInt();
}
}
int mod=0;
for(int i=1;i<=(n>>1);i++){
for(int j=1;j<=n;j++){
if(vis[i][j]!=vis[n-i+1][n-j+1])mod++;
}
}
if((n&1)==1){
for(int i=1;i<=(n>>1);i++){
if(vis[(n>>1)+1][i]!=vis[(n>>1)+1][n-i+1])mod++;
}
if(mod<=k){
System.out.println("YES");
}else{
System.out.println("NO");
}
}else{
if(mod<=k&&((k-mod)&1)==0){
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
}
}
J - Playing in a Casino
大意:给出一个T组样例,每组样例给出一个n和m表示给出n条数据,每条有m个数据
每次选两条,每个数据一一对应相减取绝对值,求绝对值的和是多少。
题解:首先一眼模拟暴力,但是时间复杂度n立方,果然超时。
我们可以考虑对列排序,因为改变行的位置不会影响结果。经过从小到大排序后,就简化为两两数字差值的问题了。
先假设有一些数字的差值为1,2,3,4,5,我们会发现
每个差值的最后相加的数量=该层及前面的层数*该层有多少个
最后需要注意答案要用long类型接收
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
/*
*@filename: Demo1
*@author: lyh
*@date:2023/4/24 19:09
*@version 1.0
*@description TODO
*/
public class Demo1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0) {
int n=scanner.nextInt();
int m=scanner.nextInt();
List<List<Integer>> vis=new ArrayList<>();
for(int i=1;i<=n;i++){
List<Integer> x=new ArrayList<>();
for(int j=1;j<=m;j++){
int num=scanner.nextInt();
x.add(num);
}
vis.add(x);
}
long sum=0;
for(int i=0;i<m;i++){
int finalI = i;//闭包
vis.sort(new Comparator<List<Integer>>() {//对列排序
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
return o1.get(finalI)-o2.get(finalI);
}
});
List<Integer>column=new ArrayList<>();
for(int j=1;j<n;j++){
column.add(vis.get(j).get(i)-vis.get(j-1).get(i));
}
int size=column.size();
for(int j=0;j<size;j++){
sum=sum+ (long) column.get(j) *(size-j)*(j+1);
}
}
System.out.println(sum);
}
}
}
K - Showstopper
大意: 两组数a、b,a1,a2,......an,b1,b2......bn。每次操作可以把对位的an与bn交换,问是否可以经过多次操作使得an和bn(即最后一个数)分别在数组a、数组b中最大
题解:整体是先从末尾出发往前走,首先处理一下末尾:
如果末尾不是最大的,并且对位元素要大一些,那就交换(贪心思想)。
然后往前遍历,如果当前元素大于末尾元素,并且对位元素也大于末尾元素(说明交换也无法挽救),那么就达不到要求。
import java.util.*;
/*
*@filename: Demo2
*@author: lyh
*@date:2023/4/25 14:46
*@version 1.0
*@description TODO
*/
public class Demo2 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while(t-->0) {
int n = scanner.nextInt();
List<Integer> vis1 = new ArrayList<>();
List<Integer> vis2 = new ArrayList<>();
for (int i = 0; i < n; i++) {
int x = scanner.nextInt();
vis1.add(x);
}
for (int i = 0; i < n; i++) {
int x = scanner.nextInt();
vis2.add(x);
}
int maxElement1 = Collections.max(vis1);//最大元素
int maxElement2 = Collections.max(vis2);//最大元素
if (maxElement1 > vis1.get(n - 1) && vis2.get(n - 1) > vis1.get(n - 1)) {
int temp = vis1.get(n - 1);
vis1.set(n - 1, vis2.get(n - 1));
vis2.set(n - 1, temp);
} else if (maxElement2 > vis2.get(n - 1) && vis1.get(n - 1) > vis2.get(n - 1)) {
int temp = vis1.get(n - 1);
vis1.set(n - 1, vis2.get(n - 1));
vis2.set(n - 1, temp);
}
int pointer = n - 2;
boolean ans = true;
while (pointer >= 0) {
if (vis1.get(pointer) > vis1.get(n - 1)) {
if (vis2.get(pointer) > vis1.get(n - 1)||vis1.get(pointer)>vis2.get(n-1)) {
System.out.println("NO");
ans = false;
break;
}
}
if (vis2.get(pointer) > vis2.get(n - 1)) {
if (vis1.get(pointer) > vis2.get(n - 1)||vis2.get(pointer)>vis1.get(n-1)) {
System.out.println("NO");
ans = false;
break;
}
}
pointer--;
}
if(ans) System.out.println("YES");
}
}
}