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");
        }
    }
}
 
                



![[Linux]文档搜索和归档备份](https://img-blog.csdnimg.cn/8abc719a57fc46e19557a5183f1de9b1.png)














